Gunicorn et Uvicorn en production — le tuning de workers que nous appliquons réellement
12 mai 2026 · 1 min de lecture · par Sudhanshu K.
Les services web Python en 2026 se divisent en deux camps : WSGI traditionnel (Django, Flask) servi via des workers sync Gunicorn, et ASGI moderne (FastAPI, Starlette, Django 5 async) servi via des workers Uvicorn sous un master Gunicorn. Les deux peuvent être de qualité prod. Aucun ne marche bien aux défauts.
La mauvaise config la plus courante que nous voyons : 2 × CPU + 1 workers tournant contre une app ASGI async qui devrait être un worker Uvicorn par cœur sans multiplicateur de concurrence. Le CPU reste inactif parce que chaque worker est mono-thread et que async tourne dans un seul event loop.
Le pattern Gunicorn + Uvicorn pour 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 -Un worker Uvicorn par cœur. Chaque worker fait tourner un event loop mono-thread. La concurrence async vient de l'attente d'I/O, pas du threading.
L'article complet couvre :
- La formule sync-worker
(2 × CPU) + 1et où elle est fausse - Pourquoi
--max-requestscompte (memory creep lent, fragmentation GC) --timeoutvs--graceful-timeout— et l'ordre dans lequel ils s'enclenchent- Quand
gthread(sync avec threads) est le bon choix - ProxyHeadersMiddleware pour la chaîne X-Forwarded-For
- Lire
gunicorn --print-configpour vérifier ce qui est réellement chargé
Nous livrons cette configuration sur chaque service Python managé.
Article complet disponible
Lire l'article complet