Gunicorn có 3 worker type chính, mỗi cái hợp một loại workload. sync (mặc định) một request một worker, blocking I/O — đơn giản, hợp CPU-bound hoặc app I/O nhanh. gthread dùng pool thread cho mỗi worker — tốt cho I/O-bound (DB query nhiều, gọi external API). uvicorn.workers.UvicornWorker async, dùng với ASGI app khi cần WebSocket hoặc async view.
gunicorn config.wsgi:application \
--workers 5 \
--worker-class gthread \
--threads 8 \
--bind 0.0.0.0:8000 \
--timeout 30 \
--max-requests 1000 \
--max-requests-jitter 100 \
--access-logfile - --error-logfile -Mấy quy tắc kinh nghiệm: workers = 2 * CPU_cores + 1 (theo Gunicorn docs); threads chỉ dùng với gthread, 4-8 thường đủ; max-requests rotate worker định kỳ để né memory leak (hay gặp với numpy/pandas trong long-running process); timeout phải đủ cho view chậm nhất chạy xong, lâu hơn thì đẩy ra background task chứ đừng tăng timeout vô tội vạ.
Quá nhiều worker tốn RAM (mỗi worker load một bản app vào memory); quá ít gây backlog dẫn tới 502. Không có "magic number" cho mọi app — đo bằng htop + gunicorn --stats rồi điều chỉnh.
Gunicorn has three main worker types, each fits a workload:
sync(default) — one request per worker, blocking I/O. Simple, fits CPU-bound or apps with fast I/O.gthread— thread pool per worker. Good for I/O-bound work (heavy DB queries, external API calls).uvicorn.workers.UvicornWorker— async, used with ASGI apps when you need WebSocket / async views.
gunicorn config.wsgi:application \
--workers 5 \
--worker-class gthread \
--threads 8 \
--bind 0.0.0.0:8000 \
--timeout 30 \
--max-requests 1000 \
--max-requests-jitter 100 \
--access-logfile - --error-logfile -Rules of thumb:
- workers = 2 * CPU_cores + 1 (Gunicorn docs).
- threads only with gthread — 4-8 is usually enough.
- max-requests rotates workers periodically to avoid memory leaks (common with numpy/pandas in long-running processes).
- timeout must cover the slowest view; if longer, push it to a background task.
Pitfall: Too many workers = wasted RAM (each loads a full app copy). Too few = backlog → 502s. Measure with htop + gunicorn --stats and adjust; there is no "magic number" for every app.