部署概念¶
當部署 FastAPI 應用程式,或者實際上是任何類型的 Web API 時,您可能會關心幾個概念,使用這些概念可以找到最合適的部署應用程式的方式。
一些重要的概念是
- 安全性 - HTTPS
- 啟動時執行
- 重新啟動
- 複寫(執行的程序數量)
- 記憶體
- 啟動前的準備步驟
我們將看到它們如何影響部署。
最終目標是能夠以安全的方式為您的 API 用戶端提供服務,以避免中斷,並盡可能有效地使用計算資源(例如遠端伺服器/虛擬機器)。🚀
我會在這裡詳細說明這些概念,希望這能讓您擁有在非常不同的環境中,甚至在尚未存在的未來環境中,決定如何部署 API 的直覺。
透過考慮這些概念,您將能夠評估和設計部署您自己的 API 的最佳方式。
在接下來的章節中,我會提供更多具體的部署方法來部署 FastAPI 應用程式。
但現在,讓我們來看看這些重要的概念性想法。這些概念也適用於任何其他類型的 Web API。💡
安全性 - HTTPS¶
在上一章關於 HTTPS 的內容中,我們了解了 HTTPS 如何為您的 API 提供加密。
我們還看到 HTTPS 通常由應用程式伺服器外部的元件提供,即TLS 終止代理。
而且必須要有東西負責更新 HTTPS 憑證,它可以是同一個元件,也可以是不同的東西。
HTTPS 工具範例¶
您可以用作 TLS 終止代理的一些工具如下:
- Traefik
- 自動處理憑證更新 ✨
- Caddy
- 自動處理憑證更新 ✨
- Nginx
- 搭配外部元件(例如 Certbot)進行憑證更新
- HAProxy
- 搭配外部元件(例如 Certbot)進行憑證更新
- Kubernetes 搭配 Ingress Controller,例如 Nginx
- 搭配外部元件(例如 cert-manager)進行憑證更新
- 由雲端供應商作為其服務的一部分在內部處理(請閱讀下方 👇)
另一個選項是您可以使用執行更多工作的雲端服務,包括設定 HTTPS。它可能有一些限制或向您收取更多費用等等。但在這種情況下,您不必自己設定 TLS 終止代理。
我將在接下來的章節中向您展示一些具體的例子。
接下來要考慮的概念都與執行實際 API 的程式有關(例如 Uvicorn)。
程式與行程¶
我們會經常談到正在執行的「行程」,因此釐清它的含義以及與「程式」一詞的區別是很有幫助的。
什麼是程式¶
「程式」一詞通常用來描述許多事物:
- 您編寫的程式碼,也就是Python 檔案。
- 可以由作業系統執行的檔案,例如:
python
、python.exe
或uvicorn
。 - 在作業系統上執行中、使用 CPU 並將資料儲存在記憶體中的特定程式。這也稱為行程。
什麼是行程¶
「行程」一詞通常以更具體的方式使用,僅指在作業系統中執行的東西(如上一點所述)。
- 在作業系統上執行中的特定程式。
- 這不是指檔案,也不是指程式碼,而是特指正在被作業系統執行和管理的東西。
- 任何程式、任何程式碼,都只有在被執行時才能運作。也就是說,當有行程正在執行時。
- 行程可以由您或作業系統終止(或「結束」)。此時,它停止執行,並且無法再運作。
- 您在電腦上執行的每個應用程式背後都有一些行程,每個正在執行的程式、每個視窗等等。通常電腦開啟時,會同時執行許多行程。
- 同一個程式可以同時有多個行程在執行。
如果您查看作業系統中的「工作管理員」或「系統監視器」(或類似工具),您將能夠看到許多正在執行的行程。
例如,您可能會看到有多個行程正在執行同一個瀏覽器程式(Firefox、Chrome、Edge 等)。它們通常每個分頁執行一個行程,再加上一些其他額外的行程。
現在我們知道了行程和程式之間的區別,讓我們繼續討論部署。
開機時執行¶
在大多數情況下,當您建立 Web API 時,您希望它持續執行,不間斷,以便您的客戶端始終可以存取它。當然,除非您有特定原因只想在某些情況下執行它,但大多數情況下,您希望它持續執行並保持可用狀態。
在遠端伺服器上¶
當您設定遠端伺服器(雲端伺服器、虛擬機器等)時,您可以做的最簡單的事情就是像在本地開發時一樣,手動使用 fastapi run
(使用 Uvicorn)或類似工具。
它會在開發期間正常運作且很有用。
但是,如果您與伺服器的連線斷開,正在執行的行程可能會終止。
如果伺服器重新啟動(例如在更新或雲端供應商遷移之後),您可能不會注意到。因此,您甚至不知道必須手動重新啟動行程。所以,您的 API 就會一直處於停止狀態。😱
開機時自動執行¶
一般來說,您可能希望伺服器程式(例如 Uvicorn)在伺服器啟動時自動啟動,並且無需任何人工干預,就能讓您的 API 保持持續執行(例如 Uvicorn 執行您的 FastAPI 應用程式)。
獨立程式¶
要達成這個目標,通常會需要一個獨立程式來確保應用程式在開機時啟動。而且在許多情況下,它也會確保其他組件或應用程式也跟著啟動,例如資料庫。
用於開機啟動的工具範例¶
一些可以執行此工作的工具範例如下:
- Docker
- Kubernetes
- Docker Compose
- Docker Swarm 模式
- Systemd
- Supervisor
- 雲端供應商作為其服務的一部分,在內部處理
- 其他...
我會在後續章節中提供更具體的範例。
重新啟動¶
與確保應用程式在開機時啟動類似,您可能也希望確保它在故障後重新啟動。
我們會犯錯¶
身為人類,我們總是會犯錯誤。軟體幾乎總是在不同的地方隱藏著錯誤。🐛
而身為開發人員的我們,會在發現這些錯誤以及實作新功能(可能也會添加新的錯誤 😅)時持續改進程式碼。
自動處理的小錯誤¶
使用 FastAPI 建置 Web API 時,如果程式碼中出現錯誤,FastAPI 通常會將其限制在觸發錯誤的單一請求中。🛡
用戶端會收到該請求的500 內部伺服器錯誤,但應用程式會繼續處理後續的請求,而不是完全崩潰。
較大的錯誤 - 崩潰¶
儘管如此,還是有可能會寫出一些程式碼導致整個應用程式崩潰,使 Uvicorn 和 Python 崩潰。💥
即使如此,您可能也不希望應用程式因為一個地方的錯誤就一直停擺,您可能希望它至少能針對未損壞的路徑操作繼續運行。
崩潰後重新啟動¶
但在發生導致運行程序崩潰的嚴重錯誤的情況下,您會希望有一個外部組件負責重新啟動程序,至少幾次...
提示
...雖然如果整個應用程式立即崩潰,則可能沒有必要一直重新啟動它。但在這種情況下,您可能會在開發過程中或至少在部署後立即注意到它。
因此,讓我們關注主要的情況,也就是它可能在未來的某些特定情況下完全崩潰,並且重新啟動它仍然有意義。
您可能希望將負責重新啟動應用程式的東西作為一個外部組件,因為到那時,使用 Uvicorn 和 Python 的同一個應用程式已經崩潰,所以在同一個應用程式的相同程式碼中沒有任何東西可以處理它。
自動重新啟動的工具範例¶
在大多數情況下,用於在開機時啟動程式的工具也用於處理自動重新啟動。
例如,這可以由以下工具處理:
- Docker
- Kubernetes
- Docker Compose
- Docker Swarm 模式
- Systemd
- Supervisor
- 雲端供應商作為其服務的一部分,在內部處理
- 其他...
複製 - 程序和記憶體¶
使用 FastAPI 應用程式時,透過像是 fastapi
命令這樣的伺服器程式來執行 Uvicorn,在**單一行程**中執行一次即可同時服務多個客戶端。
但在許多情況下,您會希望同時執行多個工作行程。
多行程 - 工作行程¶
如果您的客戶端數量超過單一行程所能處理的範圍(例如,虛擬機器不夠大),而且伺服器 CPU 具有**多個核心**,則可以同時執行**多個行程**,並在它們之間分配所有請求。
當您執行同一個 API 程式的**多個行程**時,它們通常稱為**工作行程**。
工作行程和連接埠¶
記得在關於 HTTPS的說明文件中提到,在伺服器中,只有一行程式可以監聽一個連接埠和 IP 位址的組合嗎?
這仍然適用。
因此,為了能夠同時擁有**多個行程**,必須有一個**單一行程監聽一個連接埠**,然後以某種方式將通訊傳輸到每個工作行程。
每個行程的記憶體¶
現在,當程式將東西載入記憶體時,例如,將機器學習模型載入變數中,或將大型檔案的內容載入變數中,所有這些都會**消耗伺服器的部分記憶體 (RAM)**。
而多個行程通常**不共享任何記憶體**。這意味著每個正在執行的行程都有自己的物件、變數和記憶體。如果您在程式碼中消耗大量記憶體,則**每個行程**都會消耗等量的記憶體。
伺服器記憶體¶
例如,如果您的程式碼載入一個**大小為 1 GB** 的機器學習模型,當您使用 API 執行一行程式時,它將至少消耗 1 GB 的 RAM。如果您啟動**4 個行程**(4 個工作行程),每個行程都會消耗 1 GB 的 RAM。因此,您的 API 總共將消耗 **4 GB 的 RAM**。
如果您的遠端伺服器或虛擬機器只有 3 GB 的 RAM,嘗試載入超過 4 GB 的 RAM 將會導致問題。 🚨
多行程 - 範例¶
在此範例中,有一個**管理行程**啟動並控制兩個**工作行程**。
這個管理行程很可能是監聽 IP 中**連接埠**的行程。它會將所有通訊傳輸到工作行程。
這些工作行程將是執行您的應用程式的行程,它們將執行主要的計算以接收**請求**並返回**回應**,並且它們將載入您放入 RAM 變數中的任何內容。
當然,除了您的應用程式之外,同一台機器可能也會執行**其他行程**。
一個有趣的細節是,每個行程使用的**CPU 百分比**會隨著時間**變化很大**,但**記憶體 (RAM)**通常保持相對**穩定**。
如果您的 API 每次執行的計算量都差不多,而且您有很多客戶端,那麼**CPU 使用率**可能*也會很穩定*(而不是快速地不斷上升和下降)。
複製工具和策略的範例¶
有幾種方法可以實現這一點,我將在後續章節中詳細說明具體的策略,例如在討論 Docker 和容器時。
要考慮的主要限制是,必須有**單一**組件在**公用 IP** 上處理**連接埠**。然後它必須有一種方法將通訊**傳輸**到複製的**行程/工作者**。
以下是一些可能的組合和策略
- 使用
--workers
參數的 **Uvicorn**- 一個 Uvicorn **行程管理器**將會監聽**IP** 和**連接埠**,並且它會啟動**多個 Uvicorn 工作行程**。
- **Kubernetes** 和其他分散式**容器系統**
- **Kubernetes** 層中的某些東西會監聽**IP** 和**連接埠**。複製將透過擁有**多個容器**來實現,每個容器都運行著**一個 Uvicorn 行程**。
- 為您處理此事的**雲端服務**
- 雲端服務可能會**為您處理複製**。它可能會讓您定義**要執行的行程**或要使用的**容器映像檔**,無論如何,它很可能是一個**單一的 Uvicorn 行程**,而雲端服務將負責複製它。
提示
如果其中一些關於**容器**、Docker 或 Kubernetes 的項目您還不太了解,也不用擔心。
我會在未來的章節中詳細介紹容器映像檔、Docker、Kubernetes 等:容器中的 FastAPI - Docker。
啟動前的先前步驟¶
在許多情況下,您會希望在**啟動**應用程式**之前**執行一些步驟。
例如,您可能想要執行**資料庫遷移**。
但在大多數情況下,您只需要執行這些步驟**一次**。
因此,您會希望在啟動應用程式之前,有一個**單一行程**來執行這些**先前步驟**。
而且您必須確保即使之後您為應用程式本身啟動了**多個行程**(多個工作者),也只有一個行程在執行這些先前步驟。如果這些步驟由**多個行程**執行,它們會透過**並行**執行來**重複**工作,如果這些步驟是一些比較精細的操作,例如資料庫遷移,它們可能會彼此造成衝突。
當然,在某些情況下,多次執行先前步驟沒有問題,在這種情況下,處理起來就容易多了。
提示
另外,請記住,根據您的設定,在某些情況下,您在啟動應用程式之前**可能根本不需要任何先前步驟**。
在這種情況下,您不必擔心這些。🤷
先前步驟策略範例¶
這將**很大程度上取決於**您**部署系統**的方式,並且可能與您啟動程式、處理重新啟動等方式有關。
以下是一些可能的想法
- 在您的應用程式容器之前執行的 Kubernetes 中的「Init Container」
- 一個執行先前步驟然後啟動您的應用程式的 bash 腳本
- 您仍然需要一種方法來啟動/重新啟動*該* bash 腳本、偵測錯誤等。
提示
我會在未來的章節中提供更多關於使用容器執行此操作的具體範例:容器中的 FastAPI - Docker。
資源利用率¶
您的伺服器是一種**資源**,您可以使用您的程式來消耗或**利用** CPU 上的計算時間和可用的 RAM 記憶體。
您希望消耗/利用多少系統資源?可能很容易想到「不多」,但實際上,您可能希望消耗**盡可能多的資源而不造成系統崩潰**。
如果您付費使用了 3 台伺服器,但只用到它們一點點的 RAM 和 CPU,那麼您可能正在浪費金錢 💸,而且可能也正在浪費伺服器的電力 🌎,等等。
在這種情況下,只使用 2 台伺服器並提高它們的資源使用率(CPU、記憶體、磁碟、網路頻寬等)可能會更好。
另一方面,如果您有 2 台伺服器,並且CPU 和 RAM 的使用率達到 100%,那麼在某些時候,某個程序會要求更多記憶體,伺服器將不得不使用磁碟作為「記憶體」(這可能會慢數千倍),甚至崩潰。或者某個程序可能需要進行一些計算,並且必須等到 CPU 空閒後才能執行。
在這種情況下,最好增加一台伺服器,並在上面運行一些程序,讓所有程序都有足夠的 RAM 和 CPU 時間。
還有可能因為某些原因,您的 API 使用量會出現高峰。也許它突然爆紅,或者其他一些服務或機器人開始使用它。在這些情況下,您可能希望有多餘的資源來確保安全。
您可以設定一個目標數值,例如資源利用率介於 50% 到 90% 之間。重點是,這些可能是您想要測量並用於調整部署的主要指標。
您可以使用像 htop
這樣的簡單工具來查看伺服器中使用的 CPU 和 RAM,或每個程序使用的資源量。或者您可以使用更複雜的監控工具,這些工具可以分佈在多台伺服器上等等。
摘要¶
您在此處閱讀了一些在決定如何部署應用程式時可能需要牢記的主要概念。
- 安全性 - HTTPS
- 啟動時執行
- 重新啟動
- 複寫(執行的程序數量)
- 記憶體
- 啟動前的準備步驟
了解這些概念以及如何應用它們,應該能讓您在配置和調整部署時,擁有做出任何決策所需的直覺。🤓
在接下來的章節中,我會提供更多您可以遵循的可能策略的具體範例。🚀