Skip to content

部署概念

🌐 AI 與人類共同完成的翻譯

此翻譯由人類指導的 AI 完成。🤝

可能會有對原意的誤解,或讀起來不自然等問題。🤖

你可以透過協助我們更好地引導 AI LLM來改進此翻譯。

英文版

當你要部署一個 FastAPI 應用,或其實任何類型的 Web API 時,有幾個你可能在意的概念。掌握這些概念後,你就能找出最適合部署你應用的方式。

一些重要的概念包括:

  • 安全性 - HTTPS
  • 開機自動執行
  • 重新啟動
  • 複本(執行中的行程數量)
  • 記憶體
  • 啟動前的前置步驟

我們將看看它們如何影響部署。

最終目標是能夠以安全、避免中斷,並盡可能高效使用運算資源(例如遠端伺服器/虛擬機)的方式來服務你的 API 用戶端。🚀

我會在這裡多介紹一些這些觀念,希望能幫你建立必要的直覺,讓你能在非常不同、甚至尚未出現的未來環境中決定要如何部署你的 API。

在思考這些概念之後,你將能夠評估與設計最適合部署你自己 API 的方式。

在接下來的章節,我會提供更具體的部署 FastAPI 應用的食譜。

但現在,先來看看這些重要的概念想法。這些概念同樣適用於任何其他類型的 Web API。💡

安全性 - HTTPS

前一章關於 HTTPS 中,我們學到 HTTPS 如何為你的 API 提供加密。

我們也看到,HTTPS 通常由應用伺服器外部的元件提供,即 TLS Termination Proxy。

而且必須有某個東西負責續期 HTTPS 憑證,可能是同一個元件,也可能是不同的東西。

HTTPS 工具範例

你可以用來作為 TLS Termination Proxy 的工具包括:

  • Traefik
    • 自動處理憑證續期 ✨
  • Caddy
    • 自動處理憑證續期 ✨
  • Nginx
    • 搭配像 Certbot 這類外部元件進行憑證續期
  • HAProxy
    • 搭配像 Certbot 這類外部元件進行憑證續期
  • Kubernetes,使用如 Nginx 的 Ingress Controller
    • 搭配像 cert-manager 這類外部元件進行憑證續期
  • 由雲端供應商在其服務內部處理(見下文 👇)

另一個選項是使用能幫你做更多事情的雲端服務(包含設定 HTTPS)。它可能有一些限制或要額外付費等。但在那種情況下,你就不必自己設定 TLS Termination Proxy。

我會在後續章節展示一些具體例子。


接下來要考慮的概念都與實際執行你的 API 的程式(例如 Uvicorn)有關。

程式與行程

我們會常提到執行中的「行程(process)」,因此先釐清它的意思,以及與「程式(program)」的差異很有幫助。

什麼是程式

「程式(program)」一詞常用來描述許多東西:

  • 你寫的原始碼,也就是 Python 檔案。
  • 可由作業系統執行的檔案,例如:pythonpython.exeuvicorn
  • 在作業系統上執行中的特定程式,使用 CPU 並將資料存於記憶體。這也稱為「行程」。

什麼是行程

「行程(process)」通常以更特定的方式使用,只指作業系統中正在執行的東西(如上面最後一點):

  • 在作業系統上「執行中」的特定程式。
    • 這不是指檔案或原始碼,而是特指正在被作業系統執行並管理的那個東西。
  • 任何程式、任何程式碼,只有在「被執行」時才能做事。所以,當有「行程在執行」時才能運作。
  • 行程可以被你或作業系統終止(kill)。此時它就停止執行,無法再做任何事。
  • 你電腦上執行的每個應用程式、每個視窗等,背後都有一些行程。而且在電腦開機時,通常會同時有許多行程在跑。
  • 同一個程式可以同時有多個行程在執行。

如果你打開作業系統的「工作管理員」或「系統監控器」(或類似工具),就能看到許多正在執行的行程。

例如,你大概會看到同一個瀏覽器(Firefox、Chrome、Edge 等)會有多個行程在執行。它們通常每個分頁一個行程,外加其他一些額外行程。


現在我們知道「行程」與「程式」的差異了,繼續談部署。

開機自動執行

多數情況下,當你建立一個 Web API,你會希望它「一直在執行」,不中斷,讓客戶端隨時可用。除非你有特定理由只在某些情況下才執行,但大部分時候你會希望它持續運作並且可用。

在遠端伺服器上

當你設定一台遠端伺服器(雲端伺服器、虛擬機等),最簡單的作法就是像本機開發時一樣,手動使用 fastapi run(它使用 Uvicorn)或類似的方式。

這在「開發期間」會運作良好而且有用。

但如果你與伺服器的連線中斷,正在執行的行程很可能會死掉。

而如果伺服器被重新啟動(例如更新後、或雲端供應商進行遷移),你大概「不會注意到」。因此你甚至不知道要手動重啟行程。你的 API 就會一直掛著。😱

開機自動啟動

通常你會希望伺服器程式(例如 Uvicorn)在伺服器開機時自動啟動,且不需任何「人工介入」,讓你的 API(例如 Uvicorn 執行你的 FastAPI 應用)總是有行程在跑。

獨立程式

為了達成這點,你通常會有一個「獨立的程式」來確保你的應用在開機時會被啟動。很多情況下,它也會確保其他元件或應用一併啟動,例如資料庫。

開機自動啟動的工具範例

能做到這件事的工具包括:

  • Docker
  • Kubernetes
  • Docker Compose
  • Docker 的 Swarm 模式
  • Systemd
  • Supervisor
  • 由雲端供應商在其服務內部處理
  • 其他...

我會在後續章節給出更具體的例子。

重新啟動

和確保你的應用在開機時會執行一樣,你大概也會希望在發生失敗之後,它能「自動重新啟動」。

人都會犯錯

我們身為人,常常會犯錯。軟體幾乎總是有藏在各處的「臭蟲(bugs)」🐛

而我們開發者會在發現這些 bug 後持續改進程式碼、實作新功能(也可能順便加進新的 bug 😅)。

小錯誤自動處理

使用 FastAPI 建構 Web API 時,如果我們的程式碼出錯,FastAPI 通常會把它限制在觸發該錯誤的單次請求之中。🛡

用戶端會收到「500 Internal Server Error」,但應用會繼續處理之後的請求,而不是整個崩潰。

更嚴重的錯誤 - 當機

然而,仍可能有一些情況,我們寫的程式碼「讓整個應用當機」,使 Uvicorn 與 Python 都崩潰。💥

即便如此,你大概也不會希望應用因為某處錯誤就一直處於死亡狀態,你可能會希望它「繼續運作」,至少讓沒有壞掉的「路徑操作(path operations)」能持續服務。

當機後重新啟動

在這些會讓「執行中行程」整個崩潰的嚴重錯誤案例裡,你會希望有個外部元件負責「重新啟動」該行程,至少嘗試幾次...

Tip

...不過,如果整個應用「一啟動就立刻」崩潰,那持續無止境地重啟大概沒有意義。但在這類情況下,你很可能會在開發過程中就發現,或至少在部署後馬上注意到。

所以讓我們專注在主要情境:應用在未來某些特定案例中可能會整體崩潰,但此時重新啟動仍然是有意義的。

你大概會希望把負責重新啟動應用的東西放在「外部元件」,因為那個時候,應用本身連同 Uvicorn 與 Python 都已經掛了,在同一個應用的程式碼裡也無法做什麼。

自動重新啟動的工具範例

多數情況下,用來「在開機時啟動程式」的同一套工具,也會負責處理自動「重新啟動」。

例如,可以由下列工具處理:

  • Docker
  • Kubernetes
  • Docker Compose
  • Docker 的 Swarm 模式
  • Systemd
  • Supervisor
  • 由雲端供應商在其服務內部處理
  • 其他...

複本:行程與記憶體

在 FastAPI 應用中,使用像 fastapi 指令(執行 Uvicorn)的伺服器程式,即使只在「一個行程」中執行,也能同時服務多個客戶端。

但很多情況下,你會想同時執行多個工作行程(workers)。

多個行程 - Workers

如果你的客戶端比單一行程所能處理的更多(例如虛擬機規格不大),而伺服器 CPU 有「多核心」,那你可以同時執行「多個行程」載入相同的應用,並把所有請求分散給它們。

當你執行同一個 API 程式的「多個行程」時,通常稱為「workers(工作行程)」。

工作行程與連接埠

還記得文件中關於 HTTPS 的說明嗎:在一台伺服器上,一組 IP 與連接埠的組合只能由「一個行程」監聽?

這裡同樣適用。

因此,若要同時擁有「多個行程」,就必須有「單一行程」在該連接埠上監聽,然後以某種方式把通信傳遞給各個工作行程。

每個行程的記憶體

當程式把東西載入記憶體時,例如把機器學習模型存到變數中,或把大型檔案內容讀到變數中,這些都會「消耗一些伺服器的記憶體(RAM)」。

而多個行程通常「不共享記憶體」。這表示每個執行中的行程都有自己的東西、變數與記憶體。如果你的程式碼會用掉大量記憶體,「每個行程」都會消耗等量的記憶體。

伺服器記憶體

例如,如果你的程式碼載入一個「1 GB 大小」的機器學習模型,當你用一個行程執行你的 API,它就會至少吃掉 1 GB 的 RAM。若你啟動「4 個行程」(4 個 workers),每個會吃 1 GB RAM。總計你的 API 會吃掉「4 GB RAM」。

如果你的遠端伺服器或虛擬機只有 3 GB RAM,嘗試載入超過 4 GB 的 RAM 就會出問題。🚨

多個行程 - 範例

在這個例子中,有一個「管理行程(Manager Process)」會啟動並控制兩個「工作行程(Worker Processes)」。

這個管理行程大概就是在 IP 的「連接埠」上監聽的那個。它會把所有通信轉發到各個工作行程。

那些工作行程才是實際執行你的應用的,它們會完成主要的計算,接收「請求」並回傳「回應」,也會把你放在變數中的東西載入 RAM。

當然,同一台機器上除了你的應用之外,通常也會有「其他行程」在執行。

有個有趣的細節是,每個行程的「CPU 使用率」百分比會隨時間大幅「變動」,但「記憶體(RAM)」通常維持相對「穩定」。

如果你的 API 每次做的計算量相近,且客戶很多,那「CPU 使用率」也可能「相對穩定」(而不是快速上下起伏)。

複本與擴展的工具與策略範例

要達成這些有很多種作法。我會在後續章節(例如談到 Docker 與容器時)介紹更具體的策略。

主要的限制是:必須有「單一」元件負責處理「公開 IP」上的「連接埠」。接著它必須能把通信「轉發」到被複製的「行程/workers」。

以下是一些可能的組合與策略:

  • Uvicorn 搭配 --workers
    • 一個 Uvicorn「管理行程」會在「IP」與「連接埠」上監聽,並啟動「多個 Uvicorn 工作行程」。
  • Kubernetes 與其他分散式「容器系統」
    • 由「Kubernetes」層在「IP」與「連接埠」上監聽。複本的方式是有「多個容器」,每個容器內執行「一個 Uvicorn 行程」。
  • 由「雲端服務」替你處理
    • 雲端服務很可能「替你處理複本」。它可能讓你定義「要執行的行程」或「容器映像」,無論如何,多半會是「單一 Uvicorn 行程」,而由雲端服務負責進行複製。

Tip

先別擔心這裡提到的「容器」、Docker 或 Kubernetes 如果現在還不太懂。

我會在未來的章節進一步說明容器映像、Docker、Kubernetes 等等:容器中的 FastAPI - Docker

啟動前的前置步驟

很多情況下,你會希望在應用「啟動之前」先執行一些步驟。

例如,你可能想先執行「資料庫遷移」。

但在多數情況下,你會希望這些步驟只執行「一次」。

所以,你會希望用「單一行程」來執行那些「前置步驟」,在啟動應用之前完成。

而且即使之後你要為應用本身啟動「多個行程」(多個 workers),你也必須確保只有一個行程在跑那些前置步驟。若由「多個行程」去跑,會在「平行」中重複同樣的工作;而如果那些步驟像是資料庫遷移這類敏感操作,它們之間可能會互相衝突。

當然,也有一些情況,重複執行前置步驟不會有問題;在那種情況下就容易處理得多。

Tip

另外請記住,依照你的設定,在某些情況下你「甚至可能不需要任何前置步驟」才能啟動應用。

這種情況下,你就不用為此費心了。🤷

前置步驟策略範例

這會「高度取決於」你「部署系統」的方式,而且很可能與你如何啟動程式、處理重新啟動等有關。

以下是一些可能的做法:

  • 在 Kubernetes 中使用一個「Init Container」,它會在你的應用容器之前先執行
  • 一個 bash 腳本先跑前置步驟,然後再啟動你的應用
    • 你仍然需要有機制來啟動/重新啟動「那個」bash 腳本、偵測錯誤等

Tip

我會在未來關於容器的章節提供更具體的範例:容器中的 FastAPI - Docker

資源使用率

你的伺服器(群)是可以被「消耗/利用」的「資源」,你的程式會使用 CPU 的計算時間,以及可用的 RAM 記憶體。

你想要消耗/利用多少系統資源?直覺上可能會想「不要太多」,但實際上,你大概會希望在「不當機」的前提下「盡可能用多一點」。

如果你花錢租了 3 台伺服器,卻只用了它們少量的 RAM 與 CPU,那你可能是在「浪費金錢」💸、也「浪費伺服器電力」🌎 等。

在那種情況下,可能更好的是只用 2 台伺服器,並以更高的比例使用它們的資源(CPU、記憶體、磁碟、網路頻寬等)。

另一方面,如果你有 2 台伺服器,且你使用了它們「100% 的 CPU 與 RAM」,某個時刻一個行程會要求更多記憶體,伺服器就得用磁碟當作「記憶體」(這可能慢上數千倍),甚至「當機」。或是某個行程需要做計算時,必須等到 CPU 再度空閒。

這種情況下,最好是再加一台伺服器,並在上面跑部分行程,讓所有行程都有「足夠的 RAM 與 CPU 時間」。

也有機會因為某些原因,你的 API 使用量出現「尖峰」。也許它爆紅了,或是其他服務或機器人開始使用它。在這些情況下,你可能會希望留有一些額外資源以策安全。

你可以設定一個「目標數字」,例如資源使用率落在「50% 到 90%」之間。重點是,這些大概就是你會想測量並用來調校部署的主要指標。

你可以用像 htop 這樣的簡單工具,查看伺服器的 CPU 與 RAM 使用量,或各行程的使用量。也可以用更複雜的監控工具,分散式地監看多台伺服器,等等。

重點回顧

這裡介紹了一些你在決定如何部署應用時應該記住的主要概念:

  • 安全性 - HTTPS
  • 開機自動執行
  • 重新啟動
  • 複本(執行中的行程數量)
  • 記憶體
  • 啟動前的前置步驟

理解這些想法與如何套用它們,應能給你足夠的直覺,在設定與調整部署時做出各種決策。🤓

在接下來的章節,我會提供更多可行策略的具體範例。🚀