02-2. 基礎配置參數
⏱️ 閱讀時間: 10 分鐘 🎯 難度: ⭐⭐ (簡單)
🎯 本篇重點
掌握 Gunicorn 最重要的基礎配置參數:timeout、keepalive、max_requests、backlog 等。
📋 核心配置參數總覽
最重要的 5 個參數
| 參數 | 作用 | 默認值 | 推薦值 |
|---|---|---|---|
timeout | Worker 超時時間 | 30 秒 | 30-120 秒 |
keepalive | Keep-alive 超時 | 2 秒 | 2-10 秒 |
max_requests | Worker 重啟閾值 | 0(不重啟) | 1000-2000 |
backlog | 等待連接隊列 | 2048 | 2048-4096 |
worker_connections | Worker 並發連接數 | 1000 | 1000-10000 |
⏱️ timeout(超時時間)
什麼是 timeout?
Worker 處理單個請求的最大時間。超過這個時間,Master 會殺掉 Worker 並重啟。
工作原理
請求到達 Worker
↓
開始計時(timeout 開始)
↓
處理請求...
↓
├─ 30 秒內完成 → ✅ 正常返回
└─ 超過 30 秒 → ❌ Worker 被殺掉 → 💥 502 錯誤配置方式
# gunicorn.conf.py
# 快速 API(資料庫查詢為主)
timeout = 30 # 30 秒
# 一般 Web 應用
timeout = 60 # 1 分鐘
# 長時間處理(報表生成、大文件處理)
timeout = 120 # 2 分鐘
# WebSocket / 長連接(ASGI)
timeout = 300 # 5 分鐘
# 極端情況(不推薦)
timeout = 0 # 無限等待(危險!)命令行方式
gunicorn app:application --timeout 60timeout 常見問題
問題 1:Worker timeout 頻繁發生
症狀:
[CRITICAL] WORKER TIMEOUT (pid:12345)
[INFO] Booting worker with pid: 12346原因分析:
# ❌ 原因 1:同步阻塞代碼
def slow_view(request):
import time
time.sleep(40) # 超過 timeout = 30
return HttpResponse("Done")
# ❌ 原因 2:慢速資料庫查詢
def slow_db_view(request):
# 複雜查詢,需要 60 秒
users = User.objects.all() # 100 萬筆資料
for user in users:
user.process() # 很慢
return HttpResponse("Done")
# ❌ 原因 3:外部 API 無響應
def api_view(request):
import requests
# 外部 API 掛了,一直等待
response = requests.get('https://slow-api.com', timeout=None)
return JsonResponse(response.json())解決方案:
# ✅ 方案 1:增加 timeout
# gunicorn.conf.py
timeout = 120 # 給予更多時間
# ✅ 方案 2:優化代碼
def optimized_view(request):
# 使用分頁
users = User.objects.all()[:100]
# 使用 select_related 減少查詢
users = User.objects.select_related('profile').all()[:100]
return render(request, 'users.html', {'users': users})
# ✅ 方案 3:異步處理(Celery)
from .tasks import process_users
def async_view(request):
# 丟到背景任務處理
task = process_users.delay()
return JsonResponse({'task_id': task.id})
# ✅ 方案 4:設定 API 超時
def safe_api_view(request):
import requests
try:
response = requests.get(
'https://api.example.com',
timeout=10 # 10 秒超時
)
return JsonResponse(response.json())
except requests.Timeout:
return JsonResponse({'error': 'API timeout'}, status=504)問題 2:如何判斷合理的 timeout 值?
計算公式:
timeout = P95_響應時間 × 2 + 安全邊距
# 例子:
# P95 響應時間 = 15 秒(95% 的請求在 15 秒內完成)
# 計算:15 × 2 + 10 = 40 秒
timeout = 40測試方法:
# 1. 使用 Django Debug Toolbar 查看請求時間
pip install django-debug-toolbar
# 2. 使用 New Relic / Datadog 等監控工具
# 查看 P95、P99 響應時間
# 3. 壓力測試
ab -n 1000 -c 50 http://localhost:8000/
# 查看最慢的請求時間🔄 keepalive(保持連接)
什麼是 keepalive?
HTTP Keep-Alive 的等待時間。允許同一個 TCP 連接處理多個 HTTP 請求。
工作原理
沒有 Keep-Alive(每次都建立新連接):
請求 1:
客戶端 → 建立 TCP → 發送 HTTP → 收到回應 → 關閉連接
請求 2:
客戶端 → 建立 TCP → 發送 HTTP → 收到回應 → 關閉連接
請求 3:
客戶端 → 建立 TCP → 發送 HTTP → 收到回應 → 關閉連接
每次都要 TCP 三次握手 + 四次揮手!
總耗時:(建立連接 + 請求處理 + 關閉連接) × 3
---
有 Keep-Alive(複用連接):
客戶端 → 建立 TCP → 發送請求 1 → 收到回應
→ 發送請求 2 → 收到回應
→ 發送請求 3 → 收到回應
→ 等待 5 秒(keepalive)
→ 沒有新請求 → 關閉連接
只需一次 TCP 握手和揮手!
總耗時:建立連接 + (請求處理 × 3) + 關閉連接
節省時間:約 30-50%配置方式
# gunicorn.conf.py
# 短 keepalive(API 服務)
keepalive = 2 # 默認值
# 中等 keepalive(一般 Web 應用)
keepalive = 5
# 長 keepalive(高頻互動應用)
keepalive = 10
# 極長 keepalive(內部服務)
keepalive = 30效能影響
# 測試案例:連續發送 100 個請求
# 沒有 Keep-Alive
ab -n 100 -c 1 -k http://localhost:8000/
結果:
Time per request: 52.3 ms
# 有 Keep-Alive (keepalive=5)
ab -n 100 -c 1 -k http://localhost:8000/
結果:
Time per request: 32.1 ms
效能提升:38.5%keepalive 最佳實踐
場景 1:API 服務(大量短請求)
# gunicorn.conf.py
keepalive = 5
# 理由:
# - 客戶端經常連續發送多個 API 請求
# - 5 秒足夠完成一組操作
# - 不會長時間占用連接場景 2:靜態網站(Nginx 做 reverse proxy)
# gunicorn.conf.py
keepalive = 2 # 短一點
# Nginx 配置
# proxy_http_version 1.1;
# proxy_set_header Connection "";
# Nginx 會維護到 Gunicorn 的長連接池場景 3:內部微服務
# gunicorn.conf.py
keepalive = 30 # 較長
# 理由:
# - 服務間頻繁通訊
# - 節省大量連接建立時間
# - 內網環境,連接穩定🔁 max_requests(防止記憶體洩漏)
什麼是 max_requests?
Worker 處理 N 個請求後自動重啟。防止記憶體洩漏、資源累積。
為什麼需要?
# 記憶體洩漏範例
class MyView:
# ❌ 全局列表,不斷累積
cache = []
def handle_request(self, request):
# 每個請求都添加資料
self.cache.append(request.data)
# cache 永遠不清空!
return HttpResponse("OK")
# Worker 記憶體變化:
啟動: 100 MB
處理 1000 個請求後: 200 MB
處理 5000 個請求後: 500 MB
處理 10000 個請求後: 1000 MB → 💥 OOM Kill!配置方式
# gunicorn.conf.py
# 基礎配置
max_requests = 1000 # 處理 1000 個請求後重啟
# 添加隨機性(避免所有 workers 同時重啟)
max_requests = 1000
max_requests_jitter = 50 # 隨機 ±50
# 實際重啟範圍:950-1050 個請求工作原理
Worker 1 啟動
↓
處理請求 1, 2, 3, ... , 998, 999, 1000
↓
達到 max_requests = 1000
↓
處理完當前請求 → 優雅關閉 → Master 啟動新的 Worker 1'
↓
新 Worker 1' 記憶體重置為初始狀態 ✅max_requests 配置建議
高流量應用(頻繁重啟)
# gunicorn.conf.py
max_requests = 500 # 較少
max_requests_jitter = 50
# 理由:
# - 流量大,很快就達到 500 個
# - 頻繁重啟,確保記憶體不累積
# - 對用戶影響小(workers 多)中等流量應用
# gunicorn.conf.py
max_requests = 1000
max_requests_jitter = 100
# 平衡:
# - 不會太頻繁重啟
# - 也能防止記憶體洩漏低流量應用
# gunicorn.conf.py
max_requests = 5000
max_requests_jitter = 500
# 理由:
# - 流量低,不需要頻繁重啟
# - 減少 worker 重啟開銷記憶體敏感應用
# gunicorn.conf.py
max_requests = 100 # 非常低
max_requests_jitter = 10
# 場景:
# - 處理大文件、大資料集
# - 記憶體容易洩漏
# - 頻繁重啟確保穩定監控 max_requests 效果
# gunicorn.conf.py
def worker_exit(server, worker):
"""Worker 退出時的 hook"""
from resource import getrusage, RUSAGE_SELF
# 獲取記憶體使用情況
mem_mb = getrusage(RUSAGE_SELF).ru_maxrss / 1024
server.log.info(
f"Worker {worker.pid} exited. "
f"Memory usage: {mem_mb:.2f} MB"
)
# 日誌輸出範例:
# [INFO] Worker 12345 exited. Memory usage: 234.56 MB
# [INFO] Worker 12346 exited. Memory usage: 189.23 MB📊 backlog(連接隊列)
什麼是 backlog?
等待 Workers 處理的連接隊列大小。當所有 Workers 都忙碌時,新連接會進入隊列等待。
工作原理
流量突增場景:
等待隊列(backlog = 2048)
┌─────────────────┐
新請求 → │ 等待 等待 等待...│ → Workers(都忙碌中)
└─────────────────┘
↑ ↑
隊列頭 隊列尾
場景 1:隊列未滿(< 2048)
新請求 → 進入隊列 → 等待 Worker 空閒 → 處理 ✅
場景 2:隊列已滿(= 2048)
新請求 → ❌ 連接被拒絕 → 客戶端收到錯誤配置方式
# gunicorn.conf.py
# 默認值(適合大多數情況)
backlog = 2048
# 高流量站點
backlog = 4096
# 極高流量(需要配合系統設定)
backlog = 8192如何判斷 backlog 是否足夠?
監控指標
# Linux 系統監控
netstat -an | grep :8000 | grep SYN_RECV | wc -l
# 如果數量接近 backlog 值,說明隊列快滿了
# 查看連接被拒絕的統計
netstat -s | grep "listen queue"
# SYNs to LISTEN sockets dropped: 123 ← 有丟棄!計算公式
需要的 backlog = 峰值 RPS × 平均響應時間 × 安全係數
# 例子:
# 峰值 RPS = 500
# 平均響應時間 = 2 秒
# Workers = 4(同時只能處理 4 個)
#
# 等待的請求 = 500 × 2 - 4 = 996
# 安全係數 × 2 = 1992
# backlog 設定 = 2048 ✅backlog 最佳實踐
配置 1:一般 Web 應用
# gunicorn.conf.py
workers = 4
backlog = 2048 # 默認值足夠
# 可以處理的流量:
# - 正常:4 個並發
# - 高峰:4 個處理中 + 2048 個等待配置 2:高並發 API
# gunicorn.conf.py
workers = 8
worker_class = 'uvicorn.workers.UvicornWorker'
backlog = 4096 # 加倍
# 搭配系統設定:
# /etc/sysctl.conf
# net.core.somaxconn = 4096
# 執行:sysctl -p配置 3:微服務(內部調用)
# gunicorn.conf.py
workers = 4
backlog = 1024 # 較小
# 理由:
# - 內網環境,流量可控
# - 不需要很大的隊列
# - 節省記憶體🔌 worker_connections(Worker 並發連接)
適用於哪些 Worker?
僅適用於異步 Workers:
- ✅
gevent - ✅
eventlet - ✅
uvicorn.workers.UvicornWorker - ❌
sync(不適用) - ❌
gthread(不適用)
配置方式
# gunicorn.conf.py
# Gevent Worker
workers = 4
worker_class = 'gevent'
worker_connections = 1000 # 每個 worker 最多 1000 並發
# 總並發 = 4 × 1000 = 4000
# Uvicorn Worker
workers = 4
worker_class = 'uvicorn.workers.UvicornWorker'
worker_connections = 1000 # 默認已經很高
# 高並發需求
worker_connections = 10000📝 完整配置範例
範例 1:小型 Web 應用
# gunicorn.conf.py
import multiprocessing
# Worker 配置
workers = multiprocessing.cpu_count() * 2 + 1 # 9 (假設 4 核)
worker_class = 'sync'
threads = 1
# 超時配置
timeout = 30
keepalive = 2
# 記憶體管理
max_requests = 1000
max_requests_jitter = 50
# 網絡配置
bind = '0.0.0.0:8000'
backlog = 2048
# 日誌
loglevel = 'info'
accesslog = '-'
errorlog = '-'適用場景:
- 個人部落格、小型 CMS
- 流量:< 100 並發
- 響應快速:< 100ms
範例 2:中型 API 服務
# gunicorn.conf.py
import multiprocessing
# Worker 配置
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = 'gthread'
threads = 4
# 超時配置
timeout = 60
keepalive = 5
# 記憶體管理
max_requests = 1000
max_requests_jitter = 100
# 網絡配置
bind = '0.0.0.0:8000'
backlog = 2048
# 日誌
loglevel = 'warning'
accesslog = '/var/log/gunicorn/access.log'
errorlog = '/var/log/gunicorn/error.log'
# 效能優化
preload_app = True
worker_tmp_dir = '/dev/shm'適用場景:
- RESTful API 服務
- 流量:100-500 並發
- 有資料庫查詢和外部 API 調用
範例 3:高並發 ASGI 應用
# gunicorn.conf.py
import multiprocessing
# Worker 配置(ASGI)
workers = multiprocessing.cpu_count()
worker_class = 'uvicorn.workers.UvicornWorker'
# 超時配置(長連接支持)
timeout = 120
graceful_timeout = 30
keepalive = 20
# 記憶體管理
max_requests = 500 # 高流量時更頻繁重啟
max_requests_jitter = 50
# 網絡配置
bind = 'unix:/run/gunicorn.sock'
backlog = 4096
worker_connections = 10000
# 日誌
loglevel = 'warning'
accesslog = None # 由 Nginx 記錄
errorlog = '/var/log/gunicorn/error.log'
# 效能優化
preload_app = True
worker_tmp_dir = '/dev/shm'
# Hooks
def on_starting(server):
print(f"Starting with {workers} workers")
def worker_exit(server, worker):
from resource import getrusage, RUSAGE_SELF
mem = getrusage(RUSAGE_SELF).ru_maxrss / 1024
print(f"Worker {worker.pid} exited, memory: {mem:.2f}MB")適用場景:
- Django 3.0+ 異步應用
- WebSocket 支持
- 流量:> 500 並發
- 長連接、實時通訊
範例 4:背景任務處理
# gunicorn.conf.py
# Worker 配置
workers = 4 # 較少 workers
worker_class = 'sync'
# 超時配置(長時間任務)
timeout = 300 # 5 分鐘
keepalive = 2
# 記憶體管理(重要!防止記憶體洩漏)
max_requests = 100 # 很低
max_requests_jitter = 10
# 網絡配置
bind = '127.0.0.1:8001' # 僅內網訪問
backlog = 512 # 較小的隊列
# 日誌
loglevel = 'info'
accesslog = '/var/log/gunicorn/worker_access.log'
errorlog = '/var/log/gunicorn/worker_error.log'適用場景:
- 報表生成、數據導出
- 長時間運行的任務
- 不需要高並發
- 記憶體敏感
🎤 面試常見問題
Q1: timeout 設置多少合適?
完整答案:
timeout 的設置取決於應用類型:
一般原則:
timeout = P95_響應時間 × 2 + 10秒常見場景:
- 快速 API:30 秒(默認)
- 一般 Web 應用:60 秒
- 報表生成、文件處理:120-300 秒
- WebSocket / 長連接:300 秒或更長
注意事項:
- 不要設置太短,會導致正常請求被殺掉
- 不要設置太長,會導致問題請求長時間占用 worker
- 配合 max_requests 定期重啟 worker
監控指標:
- 如果頻繁出現 “Worker timeout”,考慮增加
- 如果很少超時,可以保持默認 30 秒
Q2: max_requests 的作用是什麼?
完整答案:
max_requests 用於防止記憶體洩漏,worker 處理 N 個請求後自動重啟。
為什麼需要:
- Python 的記憶體管理不完美,可能有洩漏
- 第三方庫可能有記憶體問題
- 全局變量、快取可能不斷累積
設置建議:
# 高流量 max_requests = 500-1000 # 中流量 max_requests = 1000-2000 # 低流量 max_requests = 5000 # 記憶體敏感 max_requests = 100-500搭配使用:
max_requests = 1000 max_requests_jitter = 100 # 添加隨機性 # 避免所有 workers 同時重啟
Q3: keepalive 有什麼作用?
完整答案:
keepalive 是 HTTP Keep-Alive 的超時時間,允許在同一個 TCP 連接上處理多個 HTTP 請求。
效能影響:
- 節省 TCP 握手時間(30-50ms)
- 減少服務器負載
- 提升用戶體驗
設置建議:
# API 服務(頻繁請求) keepalive = 5-10 # 一般 Web 應用 keepalive = 2-5 # 內部微服務 keepalive = 30注意:
- Nginx 作為反向代理時,Nginx 會維護連接池
- 不要設置太長,會占用連接資源
- 客戶端也要支持 Keep-Alive
Q4: backlog 太小會怎樣?
完整答案:
backlog 是等待隊列的大小。太小會導致:
問題:
- 連接被拒絕:客戶端收到 “Connection refused”
- 丟失請求:流量高峰時丟失部分請求
- 502 錯誤:Nginx 無法連接到 Gunicorn
判斷方法:
# 查看連接隊列統計 netstat -s | grep "SYNs to LISTEN" # 如果有數字,說明隊列已滿解決方案:
# 1. 增加 backlog backlog = 4096 # 2. 配合系統設置 # /etc/sysctl.conf net.core.somaxconn = 4096 # 3. 增加 workers workers = cpu_count() * 2 # 4. 使用異步 workers worker_class = 'uvicorn.workers.UvicornWorker'
✅ 重點回顧
五大核心參數
timeout
- Worker 處理請求的最大時間
- 默認 30 秒,根據應用調整
- 太短會殺掉正常請求,太長會積累問題
keepalive
- HTTP Keep-Alive 超時
- 默認 2 秒,API 服務建議 5-10 秒
- 節省 TCP 連接時間
max_requests
- Worker 處理 N 個請求後重啟
- 防止記憶體洩漏
- 建議 1000-2000,搭配 jitter
backlog
- 等待連接的隊列大小
- 默認 2048,高流量可設 4096
- 需配合系統設置 somaxconn
worker_connections
- 僅用於異步 workers
- Gevent/Uvicorn 的並發連接數
- 默認 1000,可調整到 10000
配置檢查清單
- timeout 根據應用響應時間設置
- keepalive 根據客戶端行為調整
- max_requests 設置為 1000-2000
- max_requests_jitter 設置為 max_requests 的 10%
- backlog 檢查是否足夠(監控連接拒絕)
- worker_connections 根據並發需求設置(異步 workers)
- 添加日誌記錄超時和重啟事件
- 監控 worker 記憶體使用情況
📚 接下來
現在你掌握了 Gunicorn 的基礎配置參數!下一篇我們會學習:
- preload_app 預載入應用
- graceful_timeout 優雅關閉
- worker_tmp_dir 臨時目錄優化
- Hook functions 生命週期鉤子
- 日誌配置進階技巧
🤓 小測驗
如果應用 P95 響應時間是 10 秒,timeout 應該設置多少?
max_requests 為什麼要加 max_requests_jitter?
keepalive 設置太長有什麼問題?
worker_connections 對 sync worker 有效嗎?
上一篇: 02-1. Workers 數量計算 下一篇: 02-3. 進階配置技巧
相關閱讀:
- 01-8. 現代方案:Gunicorn + Uvicorn Workers - 了解 ASGI 配置
- 02-1. Workers 數量計算 - Workers 數量與本章參數配合使用
最後更新:2025-10-30