Gunicorn und Uvicorn in Produktion — das Worker-Tuning, das wir tatsächlich anwenden
12. Mai 2026 · 1 Min. Lesezeit · von Sudhanshu K.
Python-Webservices teilen sich 2026 in zwei Lager: traditionelles WSGI (Django, Flask), bedient via Gunicorn-Sync-Workern, und modernes ASGI (FastAPI, Starlette, Django 5 async), bedient via Uvicorn-Workern unter einem Gunicorn-Master. Beide können Produktionsqualität haben. Keines funktioniert bei Defaults gut.
Die häufigste Fehlkonfiguration, die wir sehen: 2 × CPU + 1 Worker gegen eine async ASGI-App, die einen Uvicorn-Worker pro Core ohne Concurrency-Multiplikator haben sollte. Die CPU langweilt sich, weil jeder Worker single-threaded ist und Async in einem einzelnen Event-Loop läuft.
Das Gunicorn + Uvicorn-Pattern für FastAPI
gunicorn app.main:app \
--workers $(( $(nproc) )) \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000 \
--timeout 30 \
--graceful-timeout 30 \
--keep-alive 5 \
--max-requests 10000 \
--max-requests-jitter 1000 \
--access-logfile -Ein Uvicorn-Worker pro Core. Jeder Worker fährt einen single-threaded Event-Loop. Async-Concurrency kommt vom Awaiten auf I/O, nicht vom Threading.
Der vollständige Beitrag behandelt:
- Die Sync-Worker-Formel
(2 × CPU) + 1und wo sie falsch ist - Warum
--max-requestswichtig ist (langsamer Memory-Creep, GC-Fragmentierung) --timeoutvs--graceful-timeout— und die Reihenfolge, in der sie feuern- Wann
gthread(Sync mit Threads) die richtige Wahl ist - ProxyHeadersMiddleware für die X-Forwarded-For-Kette
gunicorn --print-configlesen, um zu verifizieren, was tatsächlich geladen ist
Wir liefern diese Konfiguration auf jedem gemanagten Python-Service aus.
Vollständiger Artikel verfügbar
Vollständigen Artikel lesen