Zum Inhalt springen
EdgeServers
Blog

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) + 1 und wo sie falsch ist
  • Warum --max-requests wichtig ist (langsamer Memory-Creep, GC-Fragmentierung)
  • --timeout vs --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-config lesen, 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