SSD Nodes Learn 🎉 VPS mula $5.50/buwan
Mga Gabay Matt ConnorNi Matt Connor · Na-update 2026-08-13

Django vs Flask sa Maliit na VPS: RAM at Workers

Alamin ang aktuwal na gastos ng Django at Flask sa 1 hanggang 2 GB VPS: RAM bawat gunicorn worker at ilang worker ang kayang patakbuhin nang tapat.

Mga gastos ng Django at Flask sa isang maliit na VPS

Sa paghahambing ng Django at Flask sa isang maliit na VPS, memory ang unang dapat isaalang-alang. Ilo-load ng Django ang object relational mapper (ORM), migration machinery, at, kung ie-enable mo ito, ang admin site sa bawat worker process na sisimulan mo. Naglo-load naman ang Flask ng router at request object. Sa isang 1 GB na server, tinutukoy ng pagkakaibang ito kung ilang worker ang magkakasya. Tinutukoy naman ng bilang ng worker kung ilang request ang maaari mong pagsabay-sabay na ma-serve.

Magiging dagdag na gastos lamang ito sa Django kung muli mong bubuuin ang mga ibinibigay nito. Kung may user accounts, sessions, at admin panel ang app, mas angkop ang Django: ang RAM para sa bawat worker ang kapalit ng code na hindi mo na kailangang isulat. Kung JSON API ito na nasa harap ng datastore na pinapatakbo mo na, mas angkop ang Flask dahil hindi mo naman kailangang i-load ang alinman sa mga built-in feature nito. Usapin ito ng pagiging angkop. Ipinapakita ng mga sukat sa ibaba kung saang panig nababagay ang app mo.

Ilang memory ang ginagamit ng isang gunicorn worker?

ChartMemory per gunicorn worker, minimal app, three workers with preload on
The data behind this chart
[
  {
    "label": "Bare Python 3.12 process",
    "rss_mb": 14,
    "pss_mb": 9
  },
  {
    "label": "Flask, one route",
    "rss_mb": 42,
    "pss_mb": 26
  },
  {
    "label": "Flask + SQLAlchemy",
    "rss_mb": 58,
    "pss_mb": 38
  },
  {
    "label": "Django, admin disabled",
    "rss_mb": 78,
    "pss_mb": 47
  },
  {
    "label": "Django, admin enabled",
    "rss_mb": 96,
    "pss_mb": 58
  }
]

Ang mga ito ang karaniwang nai-publish na sukat para sa isang hello world app na may ganitong setup sa Ubuntu 24.04 at Python 3.12: tatlong gunicorn worker at naka-enable ang preload. Ituring ang mga ito bilang minimum, dahil madaragdag pa rito ang sarili mong imports. Ang isang Django worker na naka-enable ang admin ay gumagamit ng 96 MB resident memory, habang ang proportional share nito sa memory ay 58 MB. Ang pagitan ng dalawang numerong ito ang paksa ng susunod na section.

Buuin ang parehong measurement sa sarili mong box.

sudo apt update && sudo apt install -y python3-venv
python3 -m venv /srv/site1/.venv
/srv/site1/.venv/bin/pip install django gunicorn setproctitle

I-install ang setproctitle. Kapag naka-install ito, pinapalitan ng gunicorn ang pangalan ng mga process nito ng gunicorn: master [site1] at gunicorn: worker [site1]. Dahil dito, mahahanap ng mga susunod na command ang workers ayon sa pangalan sa halip na manghula.

pgrep -af gunicorn
ps -o pid,rss,args -p $(pgrep -d, -f 'gunicorn: worker')

Ang column na rss ay ang resident set size sa kilobytes: bawat memory page na kasalukuyang hawak ng process sa RAM. Kapag pinag-add ito sa lahat ng workers, masyadong mataas ang lalabas na value. Ito ay dahil ang isang forked worker ay nagsha-share ng mga page sa parent nito at sa mga sibling worker, kaya ilang beses nabibilang ang parehong page. Sa halip, hingin sa kernel ang proportional set size (PSS), na hinahati ang bawat shared page sa mga process na nagma-map dito.

for pid in $(pgrep -f 'gunicorn: worker'); do awk -v p="$pid" '/^Pss:/ {printf "%s  %d MB\n", p, $2/1024}' /proc/$pid/smaps_rollup; done

Patakbuhin ito bilang user na may-ari ng workers, o gamit ang sudo. Ang PSS ang dapat gamitin sa pagba-budget, dahil tama ang pagsasama ng PSS samantalang hindi tama ang RSS.

Mas malaki ang Django dahil sa ginagawa ng django.setup(). Ini-import nito ang bawat entry sa INSTALLED_APPS, binubuo ang application registry, at ini-instantiate ang bawat model class kasama ang isang Python object para sa bawat field nito. Kapag idinagdag ang django.contrib.admin, nagpapatakbo ito ng admin autodiscovery. Ini-import nito ang admin module ng bawat app at isinasama ang forms at template layers.

Ini-import ng isang Flask worker ang Werkzeug at Jinja2, at doon na ito nagtatapos.

May isang mahalagang caveat: madalas maliit na bahagi lamang ang framework. Ang isang worker na nag-i-import ng cloud SDK o anumang numeric library ay maaaring gumamit ng mas maraming memory para roon kaysa sa Django. Sukatin ang aktuwal mong app bago mo ipagpalagay na framework ang problema.

Copy on write, at kung bakit binabago ng preload ang bilang

Nagfa-fork ng workers ang master process ng Gunicorn. Kaagad pagkatapos ng fork(), ibinabahagi ng child ang bawat memory page sa parent, at kumokopya lamang ang kernel ng page kapag may sumulat dito sa alinmang panig. Kaya nakadepende sa kung saang panig ng fork ito binuo kung isang beses o apat na beses umiiral sa server ang Django model registry.

Kapag naka-off ang preload_app, ini-import ng bawat worker ang application pagkatapos nitong ma-fork, kaya gumagawa ang bawat isa ng sarili nitong private copy. Kapag naka-on ito, ini-import ng master ang application nang isang beses at minamana ng mga worker ang mga page na iyon.

import gc

bind = "unix:/run/site1/gunicorn.sock"
umask = 0o007
workers = 3
timeout = 30
preload_app = True
max_requests = 500
max_requests_jitter = 50

def when_ready(server):
    gc.freeze()

Hindi pabor ang CPython sa copy on write. May reference count ang header ng bawat object, at ang pag-access sa object ay nagsusulat sa header na iyon, kaya unti-unting nakokopya ang mga shared page habang nililibot ng garbage collector ang heap. Inililipat ng gc.freeze() ang lahat ng na-allocate na hanggang sa puntong iyon sa isang permanent generation na hindi na binibisita ng collector. Dahil dito, mas marami sa mga page na iyon ang nananatiling shared. Ang when_ready ang tamang hook dahil tumatakbo ito pagkatapos ng preload at bago i-fork ang unang worker. Sukatin ang PSS bago at pagkatapos mo itong idagdag, dahil nakadepende ang matitipid sa dami ng state ng application na nabuo sa import time.

May isang cost ang preload na ikinagugulat ng ilan sa araw ng deployment. Nagpapadala ang systemctl reload ng HUP, at ang dokumentadong behavior ng gunicorn sa HUP ay i-reload ang configuration nito at magsimula ng mga bagong worker. Kapag naka-preload ang app, hindi nito muling ini-import ang iyong code, kaya hindi tumatakbo ang bagong release kahit bago ang mga worker process. Gamitin ang systemctl restart pagkatapos magbago ng code, o ang sequence na USR2 at pagkatapos ay WINCH kung kailangan mo munang hayaang matapos ang mga lumang worker.

Ilang worker ang makatwirang patakbuhin ng 1 GB VPS?

ChartWhere a 1 GB VPS goes, typical idle figures before any traffic
The data behind this chart
[
  {
    "label": "Ubuntu 24.04 base",
    "ram_mb": 190
  },
  {
    "label": "nginx",
    "ram_mb": 12
  },
  {
    "label": "PostgreSQL, default config",
    "ram_mb": 120
  },
  {
    "label": "Headroom you must leave",
    "ram_mb": 150
  },
  {
    "label": "Left for gunicorn workers",
    "ram_mb": 550
  }
]

Mga idle figure ito sa isang box na walang sineserbisyuhan. Humigit-kumulang 550 MB ang natitira para sa application worker, at hindi pa kasama rito ang memory na kakailanganin pagdating ng unang request.

Ngayon, maghati nang maingat at gumamit ng pessimistic na pagtatantiya. Kumokonsumo ng memory ang isang request habang tumatakbo ito: maaaring mag-load ang isang queryset ng ilang libong row, saka mag-render ng template. Karaniwang halos doble ng idle figure ang peak memory ng bawat worker, kaya doble ang gamitin sa budget. Kapag Django na may admin at 58 MB idle, apat na worker ang kasya sa box na ito. Kapag Flask na may SQLAlchemy at 38 MB, pito naman.

Ipinapalagay ng mungkahi ng Gunicorn na (2 x cores) + 1 na CPU ang scarce resource at hindi RAM. Sa maliit na VPS, kabaligtaran ito. Kapag busy ang host, mas mababa sa katumbas ng isang buong core ang work na makukuha mo mula sa isang shared vCPU. Mahalagang maunawaan ito bago sisihin ang code mo: lumalabas sa top bilang st figure ang CPU steal time mula sa maingay na katabing tenant.

Kung kadalasang naghihintay ang mga view mo sa database o upstream API, mas mahusay ang threads kaysa processes dito. Nagbibigay ang --worker-class gthread --workers 2 --threads 4 ng walong concurrent request sa memory cost ng dalawang worker, dahil nagse-share ang mga thread ng isang naka-load na kopya ng interpreter at framework. Dahil sa global interpreter lock, hindi makatutulong ang threads sa view na CPU-bound.

Lagyan ng swap ang box. Ang 1 GB VPS na walang swap ay nagiging killed process kapag may memory spike, samantalang ang swapfile ay ginagawang mabagal na request ang parehong spike.

sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
echo 'vm.swappiness = 10' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl --system

Pagkatapos, magtakda ng limit sa mismong application. Ang MemoryMax=600M sa gunicorn unit ay nangangahulugang ibinabalik ng kernel ang memory mula sa cgroup ng app sa halip na pumili ng victim sa buong box. Kaya hindi maaapektuhan ang SSH session mo ng runaway request.

Gawi sa cold start at pag-restart

ChartImport to ready, minimal app, one shared vCPU
The data behind this chart
[
  {
    "label": "Flask, one route",
    "cold_start_ms": 90
  },
  {
    "label": "Flask + SQLAlchemy",
    "cold_start_ms": 260
  },
  {
    "label": "Django, admin disabled",
    "cold_start_ms": 480
  },
  {
    "label": "Django, admin enabled",
    "cold_start_ms": 720
  }
]

Dalawang beses binabayaran ang boot cost: sa bawat deploy at sa bawat automatic restart pagkatapos ng crash. Handa na ang isang minimal na Flask app sa loob ng humigit-kumulang 90 ms, habang humigit-kumulang 720 ms ang kailangan ng Django na naka-enable ang admin sa parehong shared vCPU. Karaniwang published figures ang dalawang ito. Sukatin ang sarili mong environment dahil ang dependencies mo ang pangunahing nakaaapekto sa resulta.

cd /srv/site1
DJANGO_SETTINGS_MODULE=site1.settings /srv/site1/.venv/bin/python -X importtime -c "import django; django.setup()" 2>&1 | tail -20

Inililista sa huling mga linya ang pinakamabagal na imports at ang cumulative microseconds ng mga ito. Para sa Flask, patakbuhin ang parehong flag laban sa iyong module: python -X importtime -c "import app".

Kapag naka-enable ang preload, isang beses lang binabayaran ng master ang cost na iyon at agad na nagsisimula ang bawat forked worker. Kapag naka-disable ang preload, bawat worker ang nagbabayad ng cost na iyon, at sinasaklaw din ng timeout ng gunicorn ang boot bukod sa request. Papatayin at papalitan ang worker na hindi nakapag-check in sa loob ng timeout segundo, kaya maaaring maipit sa restart loop ang isang mabigat na app sa mabagal na shared vCPU at hindi kailanman makapag-serve ng kahit anong request. Ganito ang nakasaad sa log:

[2026-08-09 09:14:02 +0000] [981] [CRITICAL] WORKER TIMEOUT (pid:1004)

Dapat nasa unit ang migrations, hindi sa application startup code. Isinasagawa ang ExecStartPre nang isang beses bago magsimula ang anumang worker. Kapag inilagay ang migrate sa loob ng app, mag-uunahan ang tatlong worker sa iisang schema lock.

Halos pareho ang deployment structure

Process manager

Parehong tumatakbo ang dalawang framework sa ilalim ng gunicorn, at tumatakbo naman ang gunicorn sa ilalim ng systemd.

[Unit]
Description=gunicorn for site1
After=network.target

[Service]
User=site1
Group=www-data
WorkingDirectory=/srv/site1
RuntimeDirectory=site1
Environment="PATH=/srv/site1/.venv/bin"
ExecStartPre=/srv/site1/.venv/bin/python manage.py migrate --noinput
ExecStart=/srv/site1/.venv/bin/gunicorn -c /srv/site1/gunicorn.conf.py site1.wsgi:application
Restart=on-failure
RestartSec=3
MemoryMax=600M

[Install]
WantedBy=multi-user.target

Ginagawa ng RuntimeDirectory=site1 ang /run/site1 kapag nagsisimula at inaalis ito kapag humihinto, kaya palaging umiiral ang socket path na may tamang owner. Ang linyang umask = 0o007 sa gunicorn config ang nagbibigay ng write access sa socket sa www-data group. Ito ang dahilan kung bakit naaabot ito ng nginx.

Pareho ang Flask unit sa file na ito, maliban sa isang binagong linya: ExecStart=... gunicorn -c /srv/site1/gunicorn.conf.py app:app, at walang ExecStartPre. Ang argumentong app:app ay module muna at callable pagkatapos, kaya ang error na Failed to find attribute 'app' in 'app'. ay nangangahulugang walang variable na ganoong pangalan ang iyong module. Pareho rin ang pattern para sa scheduled work. Pinapalitan ng systemd timer ang cron para sa Django management command nang hindi nagdaragdag ng task queue sa isang box na ganito kaliit.

Static files

Walang sine-serve na static files ang Django kapag may DEBUG = False. I-set ang STATIC_ROOT, patakbuhin ang python manage.py collectstatic, at ituro ang web server sa output directory. Kapag nilaktawan mo ang hakbang na iyon, maglo-load ang admin nang walang styling habang napupuno ang log ng Not Found: /static/admin/css/base.css.

May dalawang maayos na paraan para i-serve ang mga ito. Walang karagdagang load sa app ang nginx alias block. Ang WhiteNoise, kapag idinagdag bilang middleware, ay nagse-serve ng files mula sa worker at inaalis ang pangangailangan sa nginx block, kapalit ng kaunting worker time para sa bawat file. Sa development, sine-serve ng Flask ang sarili nitong static/ folder. Sa production, ituro naman ang proxy sa folder sa parehong dahilan.

Reverse proxy

server {
    listen 80;
    server_name example.com;

    location /static/ {
        alias /srv/site1/static/;
        expires 30d;
    }

    location / {
        proxy_pass http://unix:/run/site1/gunicorn.sock;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Sa likod ng anumang proxy, kailangang sabihin sa Django na HTTPS ang orihinal na request. Kung hindi, tatanggihan ng cross site request forgery (CSRF) checks nito ang sarili mong forms.

ALLOWED_HOSTS = ["example.com"]
CSRF_TRUSTED_ORIGINS = ["https://example.com"]
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

Kung nagpapatakbo na ang box ng containers, ginagawa ng Traefik sa harap ng ilang Docker Compose app ang parehong trabaho gamit ang labels sa container sa halip na isang file para sa bawat site.

Aling database

Talagang sapat ang SQLite para sa isang application server na may write rate na ilang writes bawat segundo, at inaalis nito ang isang buong daemon sa memory budget. I-on ang write ahead logging (WAL) at magtakda ng busy timeout para sa driver.

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
        "OPTIONS": {
            "timeout": 20,
            "init_command": "PRAGMA journal_mode=WAL;",
        },
    }
}

Kung wala ang dalawang option na iyon, mararanasan mo ang django.db.utils.OperationalError: database is locked sa unang pagkakataong sabay mag-write ang dalawang worker, dahil bina-block ng default journal mode ang mga reader habang may write at halos agad sumusuko ang default timeout. Nasa pagpapatakbo ng SQLite sa production sa isang VPS ang mas mahabang paliwanag, kabilang kung kailan hindi na angkop ang SQLite.

Sa parehong 1 GB box, kumokonsumo ang PostgreSQL ng 120 MB mula sa budget sa itaas, dagdag pa ang isang backend process para sa bawat persistent connection. Pinananatiling bukas ng Django's CONN_MAX_AGE ang isang connection para sa bawat worker, kaya ang apat na worker ay nangangahulugan ng apat na backend. Karaniwan, sulit ang trade-off na ito. Bilangin lamang ito bago itakda ang bilang ng worker. Kung mas gusto mong ilagay ang database sa isang container kasama ng app, pagpapatakbo ng Docker sa isang VPS ang parehong trade-off na may mas mataas na minimum na resource requirement, dahil may overhead ang daemon at bawat container na mahalaga sa ganitong kaliit na setup.

Ano ang nakukuha sa mga dagdag na resource, at ano ang kapalit nito

Ang dagdag na megabytes ng Django ay kumakatawan sa mga feature na mayroon na at magkakatugma nang gumagana: ang ORM na may migrations, ang session at authentication system, ang permission model, ang form layer na may CSRF protection, ang template engine, management commands, at ang admin. Ang admin ang feature na madalas minamaliit ng mga tao. Isa itong gumaganang database editor para sa mga model mo, na may search at filters, kapalit ng isang linya sa INSTALLED_APPS.

Kabaligtaran nito ang Flask. Makukuha mo ang routing, request object, Jinja2 templates, at config object. Ang lahat ng iba pa ay mga pagpiling ikaw ang gagawa. Malaking pakinabang ito kapag maliit ang app dahil walang ORM na nilo-load kung hindi ka naman mag-i-import nito.

Ang karaniwang problema ay ang nasa pagitan ng dalawang opsyon. Magdagdag ka ng SQLAlchemy para sa mga model, Alembic para sa migrations, Flask-Login para sa sessions, Flask-WTF para sa forms at CSRF, at admin extension para sa back office, at makabubuo ka ng system na gumagamit ng memory profile ng Django ngunit walang coherence nito. May sariling release cycle ang bawat component at sariling pananaw kung paano dapat i-wire ang app. Sa puntong ito, mas matipid na sagot ang Django, kapwa sa RAM at sa oras na ginugugol mo sa upgrades.

Django kumpara sa Flask: tuntunin sa pagpapasya

Gamitin ang Django kapag may mga account, nae-edit na content, schema na patuloy na magbabago, at back office na talagang gagamitin ng isang tao. Gamitin ang Flask kapag ang app ay isang JSON interface para sa dati nang datastore, o webhook receiver na walang HTML.

Ang panghuling batayan ay isang nakasulat na listahan. Isulat ang bawat package na ii-install mo sa Flask para makuha ang feature set na kailangan mo. Kung may ORM at migration tool sa listahan, Django na talaga ang napili mo, at nagbabayad ka lang ng dagdag para makarating doon nang mas mabagal.

May isang sitwasyong tunay na mas angkop ang Flask sa maliit na hardware: maraming maliliit na service sa iisang machine. Ang bawat Flask service ay sarili nitong murang process na tumatakbo sa ilalim ng sarili nitong unit. Kapag tatlong Django site ang tumatakbo sa iisang 1 GB VPS, tatlong kopya ng framework ang sabay-sabay na nasa memorya, kaya hindi na gumagana ang dating kalkulasyon. Kung palagi itong kulang, kadalasan ay mas malaking plan ang tapat na solusyon, at mas maikli ang pag-uusap tungkol sa aktuwal na buwanang gastos ng VPS kaysa sa muling pagsulat ng gumaganang application.

Mga failure mode at ang mga string na makikita mo

Nawawala at bumabalik ang mga worker. Ini-print ng Gunicorn ang [ERROR] Worker (pid:1234) was sent SIGKILL! Perhaps out of memory?. Ini-print ito kapag pinapatay nito ang worker na hindi nakapagpadala ng timeout heartbeat, at kapag pinatay ng kernel ang process. Gamitin ang dmesg -T | grep -i "killed process" upang matukoy kung alin sa dalawa ang nangyari. Ang isang line roon ay nangangahulugang memory ang problema, kaya bawasan ang bilang ng worker o magdagdag ng swap.

400 ang response ng bawat page at sinasabi ng log ang Invalid HTTP_HOST header. Ang buong message ay Invalid HTTP_HOST header: 'example.com'. You may need to add 'example.com' to ALLOWED_HOSTS.. Tinatanggihan ng Django ang request bago ito makarating sa iyong code dahil walang laman ang ALLOWED_HOSTS o hindi nito kasama ang pangalan na ipinasa ng proxy sa Host.

Nabibigo ang mga form dahil sa Origin checking failed. Sinasabi ng page na nabigo ang CSRF verification. Nangyayari ito kapag nasa likod ng TLS-terminating proxy ang app: plain HTTP ang nakikita ng app, kaya bumubuo ito ng http:// origin at ikinukumpara iyon sa request na dumating sa https://. Itakda ang SECURE_PROXY_SSL_HEADER at CSRF_TRUSTED_ORIGINS, at kumpirmahing ipinapadala talaga ng proxy ang X-Forwarded-Proto.

Agad nagbabalik ng 502 ang nginx. Tinutukoy ng error log ang dahilan: nangangahulugan ang connect() to unix:/run/site1/gunicorn.sock failed (2: No such file or directory) na hindi tumatakbo ang unit, habang nangangahulugan ang (13: Permission denied) na umiiral ang socket ngunit hindi ito mabuksan ng nginx. Ito ay dahil sa setting ng umask at group.

Walang styling ang admin. Hindi pa tumatakbo ang collectstatic, o hindi tumutugma ang alias path sa STATIC_ROOT. Makikita sa access log ang mga 404 sa ilalim ng /static/admin/.

Nabibigo ang mga write kahit magaan ang load. Ipinapahiwatig ng database is locked mula sa SQLite na naka-off ang WAL o masyadong maikli ang busy timeout para sa dalawang worker na sabay na nagsusulat.

FAQ

Masyado bang mabigat ang Django para sa 1 GB VPS?

Hindi. Maayos na tumatakbo ang Django na may maliit na bilang ng workers, nginx sa harap, at SQLite sa likod sa 1 GB. Nagiging kapos ang resources kapag idinagdag sa parehong server ang PostgreSQL sa default settings nito, isang cache, isang background worker, at Docker. Sukatin ang proportional set size ng isang worker, i-double ito upang paghandaan ang mga peak sa request, at ihambing ang kabuuan sa natitirang memory matapos ang operating system at database.

Ilang gunicorn workers ang dapat kong patakbuhin sa isang vCPU?

Magsimula sa tatlo at magsukat. Karaniwang memory ang pangunahing limitasyon sa maliit na VPS, kaya hatiin ang RAM na natitira matapos ang operating system at database sa doble ng proportional set size ng isang worker. Kung kadalasang naghihintay ang mga view mo sa database o upstream API, gamitin ang gthread worker class na may maliit na bilang ng workers at ilang thread bawat isa. Ibinabahagi kasi ng mga thread ang isang loaded copy ng framework at mas kaunti ang memory na ginagamit nito kaysa sa mga karagdagang proseso.

Kailangan ko ba ang PostgreSQL, o sapat na ang SQLite?

Sapat ang SQLite para sa isang application server na may katamtamang write rate, at inaalis nito ang isang buong daemon sa memory budget. I-enable ang write-ahead logging at magtakda ng busy timeout. Kung hindi, mabibigo ang sabay-sabay na writes na may database is locked. Lumipat sa PostgreSQL kapag higit sa isang machine ang kailangang magsulat, o kapag kailangan mo ng feature na wala sa SQLite, gaya ng sabay-sabay na heavy writes o per-role access control.

Dapat ba akong gumamit ng uvicorn sa halip na gunicorn?

Kung mayroon ka lamang async views at may aktuwal na hinihintay na asynchronous operation. WSGI application ang Flask, kaya tumatakbo ang async view sa bagong event loop sa loob ng worker thread at natatapos bago magsimula ang susunod na request. Wala itong dagdag na concurrency. Kailangan ng Django async views ng ASGI server upang magkaroon ng pakinabang. Sa mga bagong release ng uvicorn, inilipat ang gunicorn worker class sa hiwalay na package. Basahin ang kasalukuyang dokumentasyon ng uvicorn sa halip na kopyahin ang lumang worker class flag mula sa mas lumang tutorial.

Bakit nawala ang worker ko nang walang traceback?

Ang prosesong pinatay ng kernel dahil sa out-of-memory killer ay tumatanggap ng SIGKILL at hindi makakapag-log habang isinasara ito. Dahil dito, bigla na lamang tumitigil ang application log. Napapansin ng Gunicorn ang puwang at nagpi-print ng Worker (pid:1234) was sent SIGKILL! Perhaps out of memory?. Kumpirmahin ito gamit ang dmesg -T | grep -i "killed process". Ang solusyon ay bawasan ang bilang ng workers, o gumamit ng swapfile upang maging mabagal na request ang memory spike sa halip na maging prosesong namatay.

#django#flask#python#gunicorn#deployment#vps