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

本指南說明如何最佳化以 Python 程式設計語言編寫的 Cloud Run 服務,並提供背景資訊,協助您瞭解部分最佳化作業的取捨考量。本頁資訊是一般最佳化提示的補充內容,同樣適用於 Python。

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

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

最佳化容器映像檔

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

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

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

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

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

  • 如果大型檔案在啟動時並非必要 (例如媒體資產),請考慮設定 Cloud Storage 磁碟區掛接

  • 從任何大型依附元件匯入必要子模組,或在程式碼中需要時匯入模組,而不是在應用程式啟動時載入。

最佳化 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 的多個套件,而您可能不需要為應用程式執行這項操作。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 型映像檔也較不容易受到潛在安全漏洞攻擊。部分映像檔可能不含從來源建構 Wheel 所需的元素。

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

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

使用 PYTHONUNBUFFERED 環境變數記錄

如要查看 Python 應用程式的非緩衝記錄,請設定環境變數 PYTHONUNBUFFERED。設定這個變數後,stdoutstderr 資料會立即顯示在容器記錄中,而不是保留在緩衝區,直到累積一定量的資料或串流關閉為止。

後續步驟

如需更多提示,請參閱