目錄
01-8. 現代方案:Gunicorn + Uvicorn Workers
⏱️ 閱讀時間: 12 分鐘 🎯 難度: ⭐⭐⭐ (中等) 🆕 狀態: 新專案推薦方案
🎯 本篇重點
學習現代 Django 專案(Django 3.0+)的最佳部署方案:使用 Gunicorn 管理 Uvicorn Workers。
🆕 為什麼是 Gunicorn + Uvicorn Workers?
傳統 vs 現代方案對比
# ❌ 傳統方案(WSGI)
gunicorn myproject.wsgi:application \
--workers 4 \
--worker-class sync
# ⚠️ 單純 Uvicorn(不推薦生產環境)
uvicorn myproject.asgi:application \
--workers 4
# ✅ 現代最佳方案(ASGI + Gunicorn 管理)
gunicorn myproject.asgi:application \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker為什麼不直接用 Uvicorn?
Uvicorn 的限制:
| 功能 | Uvicorn 單獨使用 | Gunicorn + Uvicorn Workers |
|---|---|---|
| 進程管理 | ⚠️ 簡單的 worker 管理 | ✅ 完整的進程管理 |
| 自動重啟 | ⚠️ 基礎支持 | ✅ 健壯的自動重啟 |
| 平滑重載 | ❌ 不支持 | ✅ 零停機時間重載 |
| Worker 監控 | ⚠️ 有限 | ✅ 完整監控 |
| 配置靈活性 | ⚠️ 較少選項 | ✅ 豐富的配置 |
| 生產環境穩定性 | ⚠️ 可用但不推薦 | ✅ 經過考驗 |
| 記憶體管理 | ⚠️ 基礎 | ✅ max_requests 等進階功能 |
結論:Gunicorn 提供更好的進程管理,Uvicorn 提供高效能的 ASGI 處理。
🏗️ 架構對比
傳統 WSGI 架構
請求流程(舊方案):
用戶請求
↓
Nginx
↓
Gunicorn Master
↓
├── Sync Worker 1 (WSGI) → Django (同步)
├── Sync Worker 2 (WSGI) → Django (同步)
├── Sync Worker 3 (WSGI) → Django (同步)
└── Sync Worker 4 (WSGI) → Django (同步)
問題:
• 每個請求阻塞一個 worker
• I/O 等待浪費 CPU
• 並發能力受限於 worker 數量現代 ASGI 架構
請求流程(新方案):
用戶請求
↓
Nginx
↓
Gunicorn Master
↓
├── Uvicorn Worker 1 (ASGI) → Django (async/await)
│ ├── 協程 1 → 處理請求 A
│ ├── 協程 2 → 處理請求 B
│ ├── 協程 3 → 處理請求 C
│ └── ... (數千協程)
│
├── Uvicorn Worker 2 (ASGI) → Django (async/await)
│ ├── 協程 1 → 處理請求 D
│ ├── 協程 2 → 處理請求 E
│ └── ... (數千協程)
│
├── Uvicorn Worker 3 (ASGI)
└── Uvicorn Worker 4 (ASGI)
優勢:
• 每個 worker 可處理數千並發
• I/O 等待時自動切換協程
• 總並發 = workers × 數千📦 安裝與配置
1. 安裝依賴
# 完整安裝(推薦)
pip install gunicorn uvicorn[standard]
# 或者分開安裝
pip install gunicorn
pip install uvicorn
pip install uvloop httptools # 效能優化組件套件說明:
gunicorn:進程管理器uvicorn:ASGI 服務器uvloop:高效能事件循環(替代 asyncio 默認循環)httptools:快速 HTTP 解析器
2. 確保 Django 配置正確
# myproject/asgi.py
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_asgi_application()檢查清單:
- ✅ Django 版本 >= 3.0
- ✅
asgi.py文件存在 - ✅ 設置了
ASGI_APPLICATION(如果使用 Channels)
3. 基礎啟動命令
# 開發環境(使用 uvicorn 直接啟動)
uvicorn myproject.asgi:application --reload --port 8000
# 生產環境(使用 Gunicorn + Uvicorn Workers)
gunicorn myproject.asgi:application \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:80004. 完整配置文件
# gunicorn.conf.py
import multiprocessing
# ============================================
# Worker 配置
# ============================================
# Workers 數量:建議等於 CPU 核心數
workers = multiprocessing.cpu_count()
# Worker 類型:使用 Uvicorn Worker(ASGI)
worker_class = 'uvicorn.workers.UvicornWorker'
# 每個 worker 的線程數(Uvicorn 使用協程,通常設為 1)
threads = 1
# ============================================
# 網絡配置
# ============================================
# 綁定地址
bind = '0.0.0.0:8000'
# 最大等待連接數
backlog = 2048
# ============================================
# 超時配置
# ============================================
# Worker 超時時間(秒)
# ASGI 應用通常需要更長的超時時間(支持長連接)
timeout = 120
# Worker 優雅關閉超時
graceful_timeout = 30
# Keep-alive 超時
keepalive = 5
# ============================================
# 記憶體管理
# ============================================
# Worker 處理 N 個請求後自動重啟(防止記憶體洩漏)
max_requests = 1000
max_requests_jitter = 50
# ============================================
# 日誌配置
# ============================================
# 日誌級別
loglevel = 'info'
# 訪問日誌
accesslog = '-' # 輸出到 stdout
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
# 錯誤日誌
errorlog = '-' # 輸出到 stderr
# ============================================
# 進程管理
# ============================================
# 進程名稱前綴
proc_name = 'myproject'
# 守護進程模式(生產環境使用 systemd 管理,建議設為 False)
daemon = False
# PID 文件
pidfile = '/var/run/gunicorn.pid'
# 用戶/組(安全性)
# user = 'www-data'
# group = 'www-data'
# ============================================
# 效能優化
# ============================================
# 預載入應用(減少啟動時間,但重載需要重啟所有 workers)
preload_app = True
# Worker 臨時目錄
worker_tmp_dir = '/dev/shm' # 使用內存文件系統(Linux)
# ============================================
# Uvicorn 特定配置
# ============================================
# 通過環境變量傳遞給 Uvicorn
# 或在啟動時使用 --worker-class 參數的額外選項🚀 不同場景的配置
場景 1:小型應用(低流量)
# gunicorn.conf.py
# 2 核 CPU,低流量
workers = 2
worker_class = 'uvicorn.workers.UvicornWorker'
bind = '0.0.0.0:8000'
timeout = 60
max_requests = 1000
loglevel = 'info'# 啟動
gunicorn myproject.asgi:application -c gunicorn.conf.py特點:
- 2 個 workers,每個可處理數千並發
- 適合個人專案或內部工具
- 記憶體占用:約 200-400 MB
場景 2:中型應用(中等流量)
# gunicorn.conf.py
import multiprocessing
# 4-8 核 CPU,中等流量
workers = multiprocessing.cpu_count() # 動態根據 CPU
worker_class = 'uvicorn.workers.UvicornWorker'
bind = '0.0.0.0:8000'
# 較長的超時(支持 WebSocket)
timeout = 120
keepalive = 10
# 記憶體管理
max_requests = 1000
max_requests_jitter = 100
# 日誌
accesslog = '/var/log/gunicorn/access.log'
errorlog = '/var/log/gunicorn/error.log'
loglevel = 'warning'
# 預載入(加快啟動)
preload_app = True特點:
- 根據 CPU 自動設定 workers
- 支持長連接和 WebSocket
- 完整的日誌記錄
- 記憶體占用:約 800-1600 MB (8 workers)
場景 3:大型應用(高流量 + WebSocket)
# gunicorn.conf.py
import multiprocessing
import os
# 高流量配置
workers = multiprocessing.cpu_count() * 2 # 可以超過 CPU 數
worker_class = 'uvicorn.workers.UvicornWorker'
bind = 'unix:/run/gunicorn.sock' # 使用 Unix socket(更快)
# 長連接支持
timeout = 300
graceful_timeout = 60
keepalive = 20
# 高並發設定
backlog = 4096
worker_connections = 10000
# 記憶體管理
max_requests = 500 # 更頻繁重啟(高流量環境)
max_requests_jitter = 50
# 效能優化
preload_app = True
worker_tmp_dir = '/dev/shm'
# 日誌(高流量時減少日誌)
loglevel = 'warning'
accesslog = None # 禁用訪問日誌(由 Nginx 記錄)
errorlog = '/var/log/gunicorn/error.log'
# 安全配置
user = 'www-data'
group = 'www-data'
# ============================================
# Hook functions(進階)
# ============================================
def on_starting(server):
"""伺服器啟動時"""
print(f"Starting Gunicorn with {workers} workers")
def on_reload(server):
"""重載配置時"""
print("Reloading configuration")
def post_worker_init(worker):
"""Worker 初始化後"""
print(f"Worker {worker.pid} initialized")特點:
- 高並發配置(workers × 10000+ 連接)
- Unix socket(避免 TCP 開銷)
- 記憶體管理和進程自動重啟
- 適合大型 SaaS 應用
📊 效能對比測試
測試環境
硬體:4 核 CPU,8GB RAM
測試工具:wrk
測試場景:混合 API 請求(資料庫 + 外部 API)測試腳本
# views.py
import asyncio
import httpx
from django.http import JsonResponse
# 同步視圖(WSGI)
def sync_view(request):
import requests
response = requests.get('https://httpbin.org/delay/1')
return JsonResponse({'result': 'ok'})
# 異步視圖(ASGI)
async def async_view(request):
async with httpx.AsyncClient() as client:
response = await client.get('https://httpbin.org/delay/1')
return JsonResponse({'result': 'ok'})測試結果
# 測試:1000 個請求,100 並發
# 1. Gunicorn + Sync Workers (WSGI)
gunicorn myproject.wsgi:application --workers 4
結果:
Requests/sec: 4.2
Latency (avg): 23.8s
Failed: 82% ← 大量失敗!
# 2. Gunicorn + Gevent Workers (WSGI)
gunicorn myproject.wsgi:application \
--workers 4 \
--worker-class gevent \
--worker-connections 1000
結果:
Requests/sec: 95.3
Latency (avg): 1.05s
Failed: 0%
# 3. Uvicorn 單獨使用 (ASGI)
uvicorn myproject.asgi:application --workers 4
結果:
Requests/sec: 142.7
Latency (avg): 700ms
Failed: 0%
# 4. Gunicorn + Uvicorn Workers (ASGI) ✅
gunicorn myproject.asgi:application \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker
結果:
Requests/sec: 148.5 ← 最快!
Latency (avg): 673ms
Failed: 0%
Stability: ✅ 最穩定結論:
- Gunicorn + Uvicorn Workers 效能最佳且最穩定
- 比傳統 Sync Workers 快 35 倍
- 比 Gevent 快 1.5 倍
- 比單獨 Uvicorn 更穩定
🔍 與其他方案的對比
完整對比表
| 特性 | Sync | Gevent | Gthread | Uvicorn 單獨 | Gunicorn + Uvicorn |
|---|---|---|---|---|---|
| 技術基礎 | 多進程 | 進程 + Greenlet | 進程 + 線程 | 進程 + asyncio | 進程管理 + asyncio |
| Django 支持 | ✅ All | ✅ WSGI | ✅ WSGI | ✅ 3.0+ ASGI | ✅ 3.0+ ASGI |
| 並發模型 | 阻塞 | 協程 (Greenlet) | 線程 | 協程 (asyncio) | 協程 (asyncio) |
| 語法 | 同步 | 同步風格 | 同步 | async/await | async/await |
| Monkey Patch | 不需要 | ⚠️ 必須 | 不需要 | 不需要 | 不需要 |
| 單 Worker 並發 | 1 | 1000+ | 線程數 | 數千 | 數千 |
| 進程管理 | ✅ 完整 | ✅ 完整 | ✅ 完整 | ⚠️ 基礎 | ✅ 完整 |
| 自動重啟 | ✅ | ✅ | ✅ | ⚠️ 基礎 | ✅ |
| 平滑重載 | ✅ | ✅ | ✅ | ❌ | ✅ |
| WebSocket | ❌ | ⚠️ 需額外配置 | ❌ | ✅ 原生 | ✅ 原生 |
| 長期維護 | ✅ 穩定 | ⚠️ 過時 | ✅ 可用 | ✅ 推薦 | ✅✅ 最推薦 |
| 生產環境成熟度 | ✅✅ | ✅ | ✅ | ⚠️ 改進中 | ✅✅ |
| 效能(I/O 密集) | ⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 效能(CPU 密集) | ⭐⭐⭐⭐⭐ | ⭐ | ⭐⭐ | ⭐⭐ | ⭐⭐ |
💻 實際應用範例
範例 1:混合同步/異步視圖
# views.py
import asyncio
import httpx
import requests
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from asgiref.sync import sync_to_async
from .models import Product
# 同步視圖(向後兼容)
@require_http_methods(["GET"])
def sync_product_list(request):
"""舊的同步視圖,仍然可以工作"""
products = Product.objects.all()[:10]
return JsonResponse({
'products': list(products.values())
})
# 異步視圖(推薦)
@require_http_methods(["GET"])
async def async_product_list(request):
"""新的異步視圖,效能更好"""
# 異步資料庫查詢
products = await sync_to_async(
lambda: list(Product.objects.all()[:10].values())
)()
return JsonResponse({'products': products})
# 複雜異步視圖(呼叫多個外部 API)
async def async_dashboard(request):
"""並發呼叫多個 API"""
async with httpx.AsyncClient() as client:
# 同時發送多個請求
weather_task = client.get('https://api.weather.com/current')
news_task = client.get('https://api.news.com/latest')
stocks_task = client.get('https://api.stocks.com/prices')
# 等待所有請求完成
weather, news, stocks = await asyncio.gather(
weather_task,
news_task,
stocks_task
)
return JsonResponse({
'weather': weather.json(),
'news': news.json(),
'stocks': stocks.json()
})範例 2:WebSocket 支持
# routing.py (Django Channels)
from django.urls import path
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from . import consumers
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': AuthMiddlewareStack(
URLRouter([
path('ws/chat/<str:room_name>/', consumers.ChatConsumer.as_asgi()),
])
),
})
# consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
import json
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = f'chat_{self.room_name}'
# 加入群組
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# 離開群組
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
async def receive(self, text_data):
# 接收訊息並廣播
data = json.loads(text_data)
message = data['message']
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
async def chat_message(self, event):
# 發送訊息到 WebSocket
await self.send(text_data=json.dumps({
'message': event['message']
}))部署 WebSocket 應用:
# 安裝依賴
pip install channels channels-redis
# 配置文件
# gunicorn.conf.py
workers = 4
worker_class = 'uvicorn.workers.UvicornWorker'
timeout = 300 # WebSocket 需要長超時
keepalive = 60
# 啟動
gunicorn myproject.asgi:application -c gunicorn.conf.py🛠️ 部署最佳實踐
1. Systemd 服務配置
# /etc/systemd/system/gunicorn.service
[Unit]
Description=Gunicorn daemon for Django Project
After=network.target
[Service]
Type=notify
User=www-data
Group=www-data
RuntimeDirectory=gunicorn
WorkingDirectory=/var/www/myproject
ExecStart=/var/www/myproject/venv/bin/gunicorn \
myproject.asgi:application \
-c /var/www/myproject/gunicorn.conf.py
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
[Install]
WantedBy=multi-user.target啟動服務:
# 重載 systemd
sudo systemctl daemon-reload
# 啟動服務
sudo systemctl start gunicorn
# 開機自動啟動
sudo systemctl enable gunicorn
# 查看狀態
sudo systemctl status gunicorn
# 平滑重載(零停機時間)
sudo systemctl reload gunicorn2. Nginx 配置
# /etc/nginx/sites-available/myproject
upstream gunicorn_backend {
# Unix socket(推薦,效能更好)
server unix:/run/gunicorn.sock fail_timeout=0;
# 或 TCP socket
# server 127.0.0.1:8000 fail_timeout=0;
}
server {
listen 80;
server_name example.com;
client_max_body_size 100M;
# 靜態文件
location /static/ {
alias /var/www/myproject/static/;
expires 30d;
add_header Cache-Control "public, immutable";
}
location /media/ {
alias /var/www/myproject/media/;
expires 7d;
}
# WebSocket 支持
location /ws/ {
proxy_pass http://gunicorn_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 超時設定
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
# 一般 HTTP 請求
location / {
proxy_pass http://gunicorn_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超時設定
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}3. Docker 部署
# Dockerfile
FROM python:3.11-slim
# 設定工作目錄
WORKDIR /app
# 安裝依賴
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 複製專案
COPY . .
# 收集靜態文件
RUN python manage.py collectstatic --noinput
# 暴露端口
EXPOSE 8000
# 啟動命令
CMD ["gunicorn", "myproject.asgi:application", \
"--workers", "4", \
"--worker-class", "uvicorn.workers.UvicornWorker", \
"--bind", "0.0.0.0:8000", \
"--timeout", "120", \
"--access-logfile", "-", \
"--error-logfile", "-"]# docker-compose.yml
version: '3.8'
services:
web:
build: .
command: gunicorn myproject.asgi:application \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000
volumes:
- .:/app
- static_volume:/app/static
- media_volume:/app/media
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
- redis
db:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=myproject
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
redis:
image: redis:7-alpine
ports:
- "6379:6379"
nginx:
image: nginx:alpine
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- static_volume:/static:ro
- media_volume:/media:ro
ports:
- "80:80"
depends_on:
- web
volumes:
postgres_data:
static_volume:
media_volume:🐛 常見問題與解決
問題 1:Workers 頻繁重啟
症狀:
[ERROR] Worker timeout (pid:12345)
[INFO] Booting worker with pid: 12346原因:
- 同步阻塞代碼在異步視圖中運行
- CPU 密集型任務阻塞事件循環
- 超時設定太短
解決方案:
# ❌ 錯誤:在異步視圖中使用同步阻塞代碼
async def bad_view(request):
import time
time.sleep(10) # 阻塞整個 worker!
return JsonResponse({'result': 'bad'})
# ✅ 正確:使用 asyncio.sleep
async def good_view(request):
await asyncio.sleep(10) # 不阻塞,可以處理其他請求
return JsonResponse({'result': 'good'})
# ✅ 正確:CPU 密集任務移到線程池
from concurrent.futures import ThreadPoolExecutor
import asyncio
executor = ThreadPoolExecutor(max_workers=4)
async def cpu_intensive_view(request):
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(
executor,
heavy_computation # CPU 密集函數
)
return JsonResponse({'result': result})問題 2:資料庫連接池耗盡
症狀:
django.db.utils.OperationalError: too many connections解決方案:
# settings.py
# 方案 1:增加連接池大小
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydb',
'CONN_MAX_AGE': 600,
'OPTIONS': {
'connect_timeout': 10,
}
}
}
# 方案 2:使用異步資料庫驅動
# pip install psycopg[binary,pool]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydb',
'CONN_MAX_AGE': None, # 持久連接
}
}
# 方案 3:限制並發連接
# gunicorn.conf.py
workers = 4 # 減少 workers
worker_connections = 1000 # 不要設太高問題 3:記憶體持續增長
症狀:
Worker memory: 500MB → 1GB → 1.5GB → OOM Kill解決方案:
# gunicorn.conf.py
# 1. 自動重啟 workers
max_requests = 1000 # 處理 1000 個請求後重啟
max_requests_jitter = 50 # 添加隨機性,避免同時重啟
# 2. 設定記憶體限制(需要額外工具)
# 使用 supervisor 或 systemd 限制記憶體
# 3. 監控記憶體
import psutil
import os
def post_request(worker, req, environ, resp):
"""每個請求後檢查記憶體"""
process = psutil.Process(os.getpid())
mem_mb = process.memory_info().rss / 1024 / 1024
if mem_mb > 500: # 超過 500MB
worker.log.warning(f"Worker memory high: {mem_mb:.2f}MB")問題 4:WebSocket 連接斷開
症狀:
WebSocket connection closed unexpectedly解決方案:
# gunicorn.conf.py
# 1. 增加超時時間
timeout = 300 # 5 分鐘
keepalive = 60
# 2. Nginx 配置
# location /ws/ {
# proxy_read_timeout 300s;
# proxy_send_timeout 300s;
# }
# 3. 客戶端實現心跳
# JavaScript
const ws = new WebSocket('ws://example.com/ws/chat/');
// 每 30 秒發送心跳
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({type: 'ping'}));
}
}, 30000);📊 監控與日誌
1. 基礎監控
# gunicorn.conf.py
def pre_request(worker, req):
"""請求開始時"""
worker.log.info(f"{req.method} {req.path}")
def post_request(worker, req, environ, resp):
"""請求結束時"""
worker.log.info(f"{req.method} {req.path} - {resp.status}")
def worker_exit(server, worker):
"""Worker 退出時"""
server.log.info(f"Worker {worker.pid} exited")2. 效能監控(使用 Prometheus)
# 安裝
# pip install prometheus-client
# middleware.py
from prometheus_client import Counter, Histogram
import time
REQUEST_COUNT = Counter(
'django_request_count',
'Total request count',
['method', 'endpoint', 'status']
)
REQUEST_LATENCY = Histogram(
'django_request_latency_seconds',
'Request latency',
['method', 'endpoint']
)
class PrometheusMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start_time = time.time()
response = self.get_response(request)
duration = time.time() - start_time
REQUEST_COUNT.labels(
method=request.method,
endpoint=request.path,
status=response.status_code
).inc()
REQUEST_LATENCY.labels(
method=request.method,
endpoint=request.path
).observe(duration)
return response
# urls.py
from django.urls import path
from prometheus_client import make_asgi_app
urlpatterns = [
# ...
path('metrics/', make_asgi_app()), # Prometheus metrics endpoint
]✅ 重點回顧
為什麼選擇 Gunicorn + Uvicorn Workers?
Gunicorn 提供:
- ✅ 成熟的進程管理
- ✅ 自動重啟和錯誤恢復
- ✅ 平滑重載(零停機時間)
- ✅ 豐富的配置選項
- ✅ 生產環境驗證
Uvicorn Workers 提供:
- ✅ 高效能 ASGI 實現
- ✅ asyncio 原生支持
- ✅ WebSocket 支持
- ✅ 現代 Python async/await 語法
- ✅ 優秀的效能(uvloop + httptools)
配置清單
- 安裝
gunicorn和uvicorn[standard] - Django 版本 >= 3.0
- 創建
gunicorn.conf.py配置文件 - Workers 數量 = CPU 核心數
- Worker class =
uvicorn.workers.UvicornWorker - 設定合理的 timeout(60-300 秒)
- 配置 max_requests(1000-2000)
- 設定日誌級別和路徑
- Nginx 反向代理配置
- Systemd 服務配置
效能優勢
| 指標 | Sync Workers | Gevent | Gunicorn + Uvicorn |
|---|---|---|---|
| I/O 密集效能 | ⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 並發能力 | 低 | 高 | 非常高 |
| WebSocket | ❌ | ⚠️ | ✅ |
| 現代語法 | ❌ | ❌ | ✅ |
| 長期支持 | ✅ | ⚠️ | ✅ |
📚 延伸學習
相關主題
Django Async Views
- 學習如何編寫異步視圖
- 異步 ORM 查詢(Django 4.1+)
- 異步中間件
Django Channels
- WebSocket 和長連接
- 實時通訊應用
- Channel Layers(Redis)
效能優化
- 資料庫查詢優化
- 快取策略(Redis)
- CDN 配置
推薦資源
🤓 小測驗
為什麼不直接使用 Uvicorn 而要加 Gunicorn?
Workers 數量應該設定為多少?
如何判斷是否該使用這個方案?
如何在異步視圖中處理 CPU 密集任務?
上一篇: 01-7. Worker 如何選擇 下一篇: 02-1. Workers 數量計算
最後更新:2025-10-30