針對 Cloud Run 最佳化 Python 應用程式

本指南介紹了用 Python 程式語言編寫的 Cloud Run 服務的最佳化方法,以及背景信息,以幫助您瞭解某些優化中涉及的權衡取捨。本頁資訊是一般最佳化提示的補充說明,同樣適用於 Python。

許多常見的 Python 網頁應用程式最佳做法和最佳化作業,都與下列項目有關:

  • 處理並行要求 (包括以執行緒為基礎和非封鎖 I/O)
  • 使用連線集區和批次處理非重要函式,縮短回應延遲時間,例如將追蹤記錄和指標傳送至背景工作。

最佳化容器映像檔

使用下列方法最佳化容器映像檔,縮短載入和啟動時間:

  • 盡量減少啟動時載入的檔案
  • 最佳化 WSGI 伺服器

盡量減少啟動時載入的檔案

為縮短啟動時間,請只在啟動時載入必要檔案,並縮減檔案大小。如果是大型檔案,請考慮下列做法:

  • 將大型檔案 (例如 AI 模型) 儲存在容器中,加快存取速度。建議在啟動後或執行階段載入這些檔案。

  • 考慮配置雲端儲存卷掛載對於啟動時並非至關重要的大型文件,例如媒體資源。

  • 僅從任何大型依賴項中導入必需的子模組,或在程式碼需要時導入模組,而不是在應用程式啟動時載入它們。

最佳化 WSGI 伺服器

Python 透過實作 WSGI 標準 PEP-3333,將應用程式與網路伺服器互動的方式標準化。gunicorn 是較常見的 WSGI 伺服器之一,許多說明文件範例都使用這個伺服器。

最佳化 gunicorn

將以下 CMD 加入 Dockerfile 中,以最佳化 gunicorn 的呼叫:

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

如要變更這些設定,請根據每個應用程式調整工作站和執行緒的數量。舉例來說,您可以嘗試使用與可用核心數相同的 Worker 數量,確認效能有所提升,然後調整執行緒數量。設定過多工作人員或執行緒可能會造成負面影響,例如冷啟動延遲時間較長、耗用更多記憶體、每秒要求數較少等。

根據預設,gunicorn 會在啟動時產生工作站,並監聽指定連接埠,即使在評估應用程式程式碼之前也是如此。在這種情況下,您應為服務設定自訂啟動探測,因為 Cloud Run 預設啟動探測會在容器執行個體開始監聽 $PORT 時,立即將其標示為正常。

如果您想要變更此行為,可以使用 --preload 設定 呼叫 gunicorn 來評估您的應用程式程式碼,然後再進行監聽。這可以幫助:

  • 在部署時找出嚴重的執行階段錯誤
  • 節省記憶體資源

加入這項功能前,請先考量應用程式預先載入的內容。

其他 WSGI 伺服器

您不限於使用 gunicorn 在容器中執行 Python。 只要容器監聽 HTTP 通訊埠 $PORT,您就可以使用任何 WSGI 或 ASGI 網路伺服器,這符合 容器執行階段契約。

常見的替代方案包括 uwsgiuvicornwaitress

舉例來說,假設名為 main.py 的檔案包含 app 物件,下列呼叫會啟動 WSGI 伺服器:

# uwsgi: pip install pyuwsgi
uwsgi --http :$PORT -s /tmp/app.sock --manage-script-name --mount /app=main:app

# uvicorn: pip install uvicorn
uvicorn --port $PORT --host 0.0.0.0 main:app

# waitress: pip install waitress
waitress-serve --port $PORT main:app

這些項目可以新增為 Dockerfile 中的 CMD exec 行,也可以在使用 Google Cloud 建構包時,新增為 Procfile 中的 web: 項目。

優化應用程式

在 Cloud Run 服務程式碼中,您還可以最佳化以加快啟動速度並降低記憶體用量。

減少執行緒

您可以減少執行緒數量、使用非封鎖反應式策略,以及避免背景活動,藉此最佳化記憶體。此外,如一般提示頁面所述,請避免寫入檔案系統。

如要在 Cloud Run 服務中支援背景活動,請將 Cloud Run 服務設為以執行個體為準的計費方式,這樣您就能在要求以外執行背景活動,同時存取 CPU。

減少啟動工作

Python 網路型應用程式在啟動時可能需要完成許多工作,例如預先載入資料、預熱快取,以及建立連線集區。如果依序執行這些工作,速度可能會很慢。不過,如要平行執行,請增加 CPU 核心數量。

Cloud Run 向真實使用者發送請求以觸發冷啟動執行個體。 如果要求指派給新啟動的執行個體,使用者可能會遇到長時間延遲。

使用精簡的基本映像檔提升安全性

如要提升應用程式安全性,請使用套件和程式庫較少的精簡基本映像檔。

如果您選擇不在容器中從來源安裝 Python,請使用 Docker Hub 的官方 Python 基本映像檔。這些映像檔是以 Debian 作業系統為基礎。

如果您使用 Docker Hub 中的 python 映像檔,建議改用 slim 版本。這些映像檔較小,因為不包含用於建構 Wheel 的多個套件,而您可能不需要為應用程式建構 Wheel。python 映像包含 GNU C 編譯器、預處理器和核心實用程式。

如要找出基本映像檔中最大的十個套件,請執行下列指令:

DOCKER_IMAGE=python # or python:slim
docker run --rm ${DOCKER_IMAGE} dpkg-query -Wf '${Installed-Size}\t${Package}\t${Description}\n' | sort -n | tail -n10 | column -t -s $'\t'

由於這類低階套件較少,因此 slim 型映像檔也較不容易受到潛在安全漏洞攻擊。這些圖片中可能不包含從零開始組裝車輪所需的全部元素。

如要重新加入特定套件,請在 Dockerfile 中新增 RUN apt install 行。詳情請參閱「在 Cloud Run 中使用系統套件」。

此外,您也可以選擇非 Debian 架構的容器。python:alpine 選項可能會產生小得多的容器,但許多 Python 套件可能沒有支援以 Alpine 為基礎系統的預先編譯 Wheel。支援功能正在改善 (請參閱 PEP-656),但仍有差異。您也可以考慮使用 distroless base image,其中不含任何套件管理工具、殼層或其他程式。

使用 PYTHONUNBUFFERED 環境變數記錄

如要查看 Python 應用程式的未緩衝記錄,請設定環境變數 PYTHONUNBUFFERED。設定此變數後,stdoutstderr 資料將立即在容器日誌中可見,而不是保存在緩衝區中,直到累積一定量的資料或流關閉。

後續步驟

如需更多提示,請參閱