本文 AI 產出,尚未審核

FastAPI 部署與架構 – uvicorn workers 設定

簡介

在開發完 FastAPI 應用之後,最終的挑戰往往是 如何讓服務在生產環境中穩定、效能佳地運行
Uvicorn 作為 FastAPI 官方推薦的 ASGI 伺服器,提供了 --workers 參數讓我們可以同時啟動多個 worker 進程,充分利用多核心 CPU,提升併發處理能力。

如果對 workers 的概念與設定方式不熟悉,常會出現資源浪費、效能瓶頸,甚至服務不穩的問題。本文將從核心概念、實作範例、常見陷阱與最佳實踐,帶你一步步掌握 uvicorn workers 的設定,讓你的 FastAPI 應用在生產環境中跑得更快、更穩。


核心概念

1. 為什麼需要多個 worker?

  • CPU 核心利用:Uvicorn 預設是單執行緒的 asyncio 事件迴圈,只有一個 CPU 核心在工作。透過 --workers N,Uvicorn 會 fork 出 N 個獨立的 Python 進程,每個進程各自擁有自己的事件迴圈與 CPU 時間片,能夠同時處理更多請求。
  • 容錯與穩定性:若某個 worker 發生未捕捉例外或崩潰,其他 worker 仍可繼續服務,避免整個服務瞬間斷線。
  • 記憶體與 I/O 分離:在 I/O 密集(例如大量資料庫查詢)或 CPU 密集(例如影像處理)情境下,分散工作負載能減少單一進程的記憶體與資源瓶頸。

2. 工作原理 – Pre‑fork 模式

Uvicorn 採用 pre‑fork(先 fork)方式啟動 workers:

  1. 主進程解析指令列參數,建立 socket(監聽埠)。
  2. 主進程先 fork() N 次,產生 N 個子進程(worker)。
  3. 每個 worker 繼承已建立的 socket,各自啟動自己的事件迴圈。
  4. 主進程只負責監控子進程的生命週期,發生異常時會自動重啟。

注意:因為是 fork,子進程會拷貝主進程的記憶體映射(Copy‑On‑Write),所以在啟動前 不要在全域變數中執行大量 I/O,以免造成不必要的記憶體拷貝。

3. 設定方式

Uvicorn 支援兩種常見的啟動方式:

方式 範例指令 說明
CLI uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4 直接在終端機下指令,適合簡單部署或測試。
Python 程式 uvicorn.run("app.main:app", host="0.0.0.0", port=8000, workers=4) 在自訂腳本或 Docker entrypoint 中使用,方便加入前置或後置處理。

程式碼範例

以下示範 5 個實務上常見的 uvicorn workers 設定情境,全部使用 Python 語言。

範例 1️⃣:最簡單的 CLI 啟動(4 個 workers)

uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4

只需在 Dockerfile 或 CI/CD pipeline 中加入這行指令,即可讓 FastAPI 使用四核 CPU 完全發揮效能。

範例 2️⃣:在程式內部使用 uvicorn.run

# run_server.py
import uvicorn

if __name__ == "__main__":
    # 使用 2 個 workers,適合雙核或低資源的 VM
    uvicorn.run(
        "app.main:app",
        host="0.0.0.0",
        port=8000,
        workers=2,
        log_level="info",
    )

這種寫法適合在 Docker entrypointsystemd service 中直接呼叫 python run_server.py

範例 3️⃣:根據 CPU 核心自動決定 workers 數量

# auto_workers.py
import multiprocessing
import uvicorn

def get_worker_count():
    # 留一個核心給作業系統與其他服務
    cpu_cnt = multiprocessing.cpu_count()
    return max(1, cpu_cnt - 1)

if __name__ == "__main__":
    uvicorn.run(
        "app.main:app",
        host="0.0.0.0",
        port=8000,
        workers=get_worker_count(),
        log_level="warning",
    )

最佳實踐:在雲端或容器環境中,CPU 核心數量可能會變動,此程式碼可自動調整 workers,避免手動設定錯誤。

範例 4️⃣:與 Gunicorn 結合使用 uvicorn.workers.UvicornWorker

# 在 Dockerfile 中安裝 gunicorn
pip install gunicorn

# 使用 gunicorn 指定 worker 類別
gunicorn app.main:app \
    -w 4 \
    -k uvicorn.workers.UvicornWorker \
    -b 0.0.0.0:8000 \
    --log-level info

Gunicorn 提供了 Graceful shutdown、pre‑load、max‑requests 等額外功能,適合需要更細緻控制的生產環境。

範例 5️⃣:設定 timeoutmax_requests(防止記憶體泄漏)

gunicorn app.main:app \
    -w 3 \
    -k uvicorn.workers.UvicornWorker \
    -b 0.0.0.0:8000 \
    --timeout 30 \
    --max-requests 1000 \
    --max-requests-jitter 50
  • --timeout:若 worker 超過 30 秒未回應,Gunicorn 會自動重啟。
  • --max-requests:每處理 1000 個請求後重啟 worker,可減少長時間運行所產生的記憶體泄漏。
  • --max-requests-jitter:在 0~50 之間隨機調整重啟點,避免所有 worker 同時重啟造成短暫斷線。

常見陷阱與最佳實踐

陷阱 可能的後果 解決方案 / 建議
Worker 數量過多 記憶體耗盡、CPU 爭用、效能下降 依照 CPU 核心數 設定,通常 workers = cores - 1 為佳;若容器限制記憶體,需額外測試。
在全域變數中執行 I/O (例如 DB 連線) 子進程會拷貝已建立的連線,導致 連線錯誤或資源浪費 把 DB、Redis 等連線放在 依賴注入startup 事件 中,讓每個 worker 各自建立連線。
忘記設定 --log-level 日誌過於冗長或無法追蹤錯誤 在開發環境使用 debug,在生產環境使用 infowarning
直接在 Dockerfile CMD 中使用 uvicorn,未設定 workers 只跑單一 worker,無法利用多核心 在 Dockerfile 中明確加入 --workers ${WORKERS},或使用 entrypoint.sh 讀取環境變數。
使用 --reload 與多 worker 同時啟動 --reload 只在單 worker 時有效,會產生多個重載監控,浪費資源 生產環境 絕不 同時開啟 --reload 與多 worker;開發環境僅使用單 worker。

最佳實踐

  1. 先測試單 worker,確認應用邏輯與相依套件在多進程環境下不會產生衝突(例如 global state、檔案寫入)。
  2. 使用 preload_app=True(Gunicorn):在 worker fork 前先載入應用程式,減少每個 worker 的啟動時間,但要確保所有全域資源在 fork 前是安全的。
  3. 監控與自動重啟:結合 systemdDocker 的健康檢查或 Kubernetes livenessProbe,確保 worker 異常時能自動恢復。
  4. 設定 --max-requests:長時間運行的服務容易累積記憶體碎片,定期重啟 worker 可維持穩定性。

實際應用場景

場景 為什麼需要調整 workers 推薦設定
小型單機 VM(2 核) 只需要基本併發,資源有限 workers=1(或 2-1=1
中型雲端 VM(4 核) 多使用者同時呼叫 API,I/O 密集 workers=3,加上 --max-requests 2000
CPU 密集的影像辨識服務 每個請求會佔用大量 CPU,需平衡 workers=2(保留 2 核給作業系統)+ --timeout 60
Kubernetes 部署 Pod 可能被水平擴展,需自動調整 使用環境變數 WORKERS=$(($(nproc) - 1)),在 entrypoint 中 uvicorn ... --workers $WORKERS
使用 Gunicorn 作為前置 想要利用 Gunicorn 的 graceful shutdown、log rotation gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b :8000 app.main:app

總結

  • workers 是提升 FastAPI 服務併發與容錯的關鍵參數,透過 uvicorn --workers N 或結合 GunicornUvicornWorker 可輕鬆達成。
  • 正確的 worker 數量 取決於 CPU 核心、記憶體限制與應用類型,建議以 cores - 1 為起點,並在正式環境中透過監控調整。
  • 避免在全域變數中執行 I/O,使用 依賴注入startup 事件 讓每個 worker 各自建立資源,防止 fork 後的資源衝突。
  • 結合 max‑requests、timeout、preload_app 等 Gunicorn 選項,可進一步提升穩定性與效能。

掌握 uvicorn workers 的設定,讓你的 FastAPI 應用在生產環境中 跑得更快、更穩,同時也為未來的垂直或水平擴展奠定堅實基礎。祝開發順利,服務永遠在線!