iT邦幫忙

2025 iThome 鐵人賽

DAY 10
0

昨天我們了解了 WSGI 和 ASGI 這兩個重要的溝通規範。今天,我們來認識一下將這些規範付諸實踐的關鍵角色:Application Server,特別是與 FastAPI 合作無間的 Uvicorn 和 Gunicorn。

Application Server 的職責

在我們 Day 09 提到的架構中,Application Server(也常被稱為 WSGI/ASGI Server)扮演著至關重要的翻譯官角色。它位於 Web Server (如 Nginx) 和我們的 FastAPI 應用程式之間,主要職責是:

  1. 載入應用程式:啟動並管理我們的 Python Web 應用程式實例。
  2. 解析請求:接收來自 Web Server 的原始 HTTP 請求。
  3. 遵循規範:按照 WSGI 或 ASGI 規範,將請求轉換成 Python 應用程式可以理解的格式 (例如,一個包含環境變數的字典)。
  4. 傳遞請求:呼叫我們的應用程式程式碼來處理這個請求。
  5. 打包回應:將應用程式返回的內容,打包成一個標準的 HTTP 回應,然後回傳給 Web Server。

沒有 Application Server,Nginx 不知道如何與一個 Python 物件溝通,反之亦然。

Uvicorn:為速度而生的 ASGI 伺服器

Uvicorn 是一個閃電般快速的 ASGI 伺服器,它的名字就代表了它的核心:uvloophttptoolsuvloopasyncio 事件循環的超快速替代品,這使得 Uvicorn 在處理非同步任務時性能極佳。

它在架構中的角色:Uvicorn 是專為 ASGI 打造的 Application Server。當你執行 FastAPI 應用程式時,Uvicorn 會載入你的程式碼,監聽網路埠號,並將收到的請求轉換成 ASGI 事件,交給 FastAPI 處理。

FastAPI 為何需要它?

FastAPI 的核心是非同步的,它依賴 ASGI 規範來實現高效的並行處理。因此,FastAPI 必須由一個 ASGI 伺服器來運行。Uvicorn 是 FastAPI 官方推薦的伺服器,因為它性能卓越,且與 FastAPI 和 Starlette 完美契合。

啟動一個 FastAPI 應用程式非常簡單:

# main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

在終端機中執行:

uvicorn main:app --reload

main 是指 main.py 檔案,app 是指在 main.py 中建立的 FastAPI 實例。--reload 參數會在程式碼變更時自動重啟伺服器,非常適合開發階段。

Gunicorn:成熟穩定的 WSGI 伺服器

Gunicorn (Green Unicorn) 是一個非常成熟、穩定且被廣泛使用的 WSGI 伺服器。它以其簡單的設定和強大的程序管理能力而聞名。Gunicorn 透過預先 fork 多個 Worker Process 來實現並行處理,每個 Worker 都是一個獨立的 Unix 程序,可以獨立處理請求。

它在架構中的角色:Gunicorn 是一個純粹的 WSGI 伺服器。它無法直接運行 ASGI 應用程式,如 FastAPI。

Gunicorn + Uvicorn Worker

那麼,如果 Gunicorn 這麼穩定,而 Uvicorn 性能又這麼好,我們能否將兩者結合呢?答案是肯定的!這也 曾經 是生產環境中部署 FastAPI 的推薦方式。

我們可以讓 Gunicorn 作為程序管理器 (Process Manager),並使用 Uvicorn 作為其 Worker 類別。

架構分工:

  • Gunicorn (Master Process):負責啟動、監控和管理多個 Uvicorn worker process。如果某個 worker 意外崩潰,Gunicorn 會自動重啟一個新的,確保服務的穩定性。
  • Uvicorn (Worker Process):每個 worker process 內部都運行著一個 Uvicorn 伺服器。它負責實際處理 ASGI 應用程式的請求,享受 asyncio 帶來的高性能。

這樣配置,我們既獲得了 Gunicorn 的穩定性和 multi-process 管理能力,又能享受到 Uvicorn 處理非同步請求的極致性能。

啟動指令如下:

gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app
  • -w 4:啟動 4 個 worker process。
  • -k uvicorn.workers.UvicornWorker:指定 Gunicorn 使用 Uvicorn 的 worker 類別來運行。這就是讓 Gunicorn 能夠管理 ASGI 應用的關鍵。

時代的眼淚?

前面有提到,Gunicorn + Uvicorn 的組合已經不再是推薦做法,FastAPI 在文件中也表示 tiangolo/uvicorn-gunicorn-fastapi 這個「前」官方 Docker image 已經 deprecated 了 (2024 年 8 月)。

主要有 2 個原因:

1. Uvicorn 內建 Worker 管理功能的成熟

Uvicorn 專案本身不斷發展,其內建的 Worker 管理功能也日趨完善。現在,您可以直接透過 uvicorn 指令加上 --workers 參數來啟動多個 Worker 進程:

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

這個指令會啟動一個主進程和四個 Worker 進程。Uvicorn 的主進程同樣具備了監控和重啟異常終止的 Worker 的能力。雖然其功能豐富度可能仍不及 Gunicorn,但對於大多數常見的生產環境需求而言,已經綽綽有餘,且省去了一個額外的依賴。

2. 容器化與容器編排系統的普及

現代應用程式的部署越來越依賴 Docker、Kubernetes (K8s) 等容器化技術。在這樣的架構下,進程管理和服務健康的責任,逐漸從應用程式層級轉移到了基礎設施層級。在這種模式下,Gunicorn 的角色被 K8s 等更高層級的工具所取代。在容器內僅運行 Uvicorn(帶或不帶 --workers),可以讓容器的啟動和管理更為單純。

現在的推薦做法

就直接使用 uvicorn 搭配 --workers,例如:

uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4

或是直接用 FastAPI CLI:

fastapi run --workers 4 main.py

其他部屬的細節,就等最後講到容器化與部屬時,再進行討論~

小結

FastAPI 的非同步特性決定了它需要一個 ASGI 伺服器來運行。Uvicorn 作為高性能的 ASGI 伺服器,是 FastAPI 的完美搭檔。無論是開發階段還是生產環境,現在都推薦直接使用 Uvicorn(搭配 --workers 參數)或 FastAPI CLI 來運行應用程式。隨著容器化技術的普及和 Uvicorn 自身功能的完善,這種簡潔的部署方式已經能夠滿足大多數生產環境的需求。


上一篇
[Day 09] WSGI vs. ASGI
下一篇
[Day 11] 應用程式的生命週期管理:Lifespan
系列文
用 FastAPI 打造你的 AI 服務12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言