剖析 Python 應用程式

本頁說明如何修改 Python 應用程式以擷取剖析資料,並將那些資料傳送至您的 Google Cloud專案。如需剖析作業的一般資訊,請參閱剖析概念

Python 適用的剖析類型:

  • CPU 作業時間
  • 實際時間 (主執行緒)

支援的 Python 語言版本:

  • Python 3.6 到 3.11.0。

支援的剖析代理程式版本:

  • 支援最新版本的代理程式。一般來說,我們不支援一年以上的版本。建議您使用最近發布的代理程式版本。

支援的作業系統:

  • Linux。使用 glibcmusl 實作標準 C 程式庫的 Linux kernel 支援剖析 Python 應用程式。如需 Linux Alpine kernel 專屬的設定資訊,請參閱「在 Linux Alpine 上執行」一文。

支援的環境:

啟用 Profiler API

使用剖析代理程式之前,請確保基礎 Profiler API 已啟用。您可以查看 API 狀態,或視需要使用 Google Cloud CLI 或 Google Cloud 控制台來啟用 API:

gcloud CLI

  1. 如果您尚未在工作站上安裝 Google Cloud CLI,請參閱 Google Cloud CLI 說明文件

  2. 執行下列指令:

    gcloud services enable cloudprofiler.googleapis.com
    

詳情請參閱 gcloud services

Google Cloud 控制台

  1. Enable the required API.

    Enable the API

  2. 如果畫面顯示「API enabled」,代表 API 已啟用。如果未顯示,請按一下「啟用」按鈕。

將 IAM 角色授予服務帳戶

如果您在 Google Cloud 資源上部署應用程式,且使用的是預設服務帳戶,但尚未修改該服務帳戶的角色授予權限,則可略過本節。

如果您執行下列任何操作,就必須為服務帳戶授予 Cloud Profiler 代理程式 (roles/cloudprofiler.agent) 的 IAM 角色:

  1. 您使用預設服務帳戶,但修改了其角色授予權限。
  2. 您使用的是使用者建立的服務帳戶。
  3. 您使用的是 工作負載身分,請將 Cloud Profiler Agent 角色授予 Kubernetes 服務帳戶。

您可以使用Google Cloud 控制台或 Google Cloud CLI,為服務帳戶授予 IAM 角色。舉例來說,您可以使用 gcloud projects add-iam-policy-binding 指令:

gcloud projects add-iam-policy-binding GCP_PROJECT_ID \
    --member serviceAccount:MY_SVC_ACCT_ID@GCP_PROJECT_ID.iam.gserviceaccount.com \
    --role roles/cloudprofiler.agent

使用上述指令前,請先替換以下項目:

  • GCP_PROJECT_ID:您的專案 ID。
  • MY_SVC_ACCT_ID:服務帳戶名稱。

詳情請參閱「管理專案、資料夾和機構的存取權」。

使用 Cloud Profiler

如要瞭解使用 Python 時的最佳做法,請前往設定 Python 開發環境一文。

Compute Engine

如果是 Compute Engine,請執行下列操作:

  1. 安裝 C/C++ 編譯器和開發工具:

    sudo apt-get install -y build-essential
    
  2. 安裝 pip:

    sudo apt-get install -y python3-pip
    
  3. 安裝 Profiler 套件:

    pip3 install google-cloud-profiler
    
  4. 匯入 googlecloudprofiler 模組,並盡早在初始化程式碼中呼叫 googlecloudprofiler.start 函式:

    import googlecloudprofiler
    
    
    def main():
        # Profiler initialization. It starts a daemon thread which continuously
        # collects and uploads profiles. Best done as early as possible.
        try:
            googlecloudprofiler.start(
                service="hello-profiler",
                service_version="1.0.1",
                # verbose is the logging level. 0-error, 1-warning, 2-info,
                # 3-debug. It defaults to 0 (error) if not set.
                verbose=3,
                # project_id must be set if not running on GCP.
                # project_id='my-project-id',
            )
        except (ValueError, NotImplementedError) as exc:
            print(exc)  # Handle errors here

    您必須在 start 函式中指定 service 參數。如要在 Profiler 介面中依應用程式版本進行篩選,請指定 service_version 參數。如需疑難排解和例外狀況的相關資訊,請參閱「疑難排解」一節。

GKE

如果是 GKE,請執行下列操作:

  1. 修改 Dockerfile 來安裝 Profiler 套件:

    FROM python:3
    ...
    RUN apt-get update && apt-get install -y build-essential python3-pip
    RUN pip3 install google-cloud-profiler
    
  2. 匯入 googlecloudprofiler 模組,並盡早在初始化程式碼中呼叫 googlecloudprofiler.start 函式:

    import googlecloudprofiler
    
    
    def main():
        # Profiler initialization. It starts a daemon thread which continuously
        # collects and uploads profiles. Best done as early as possible.
        try:
            googlecloudprofiler.start(
                service="hello-profiler",
                service_version="1.0.1",
                # verbose is the logging level. 0-error, 1-warning, 2-info,
                # 3-debug. It defaults to 0 (error) if not set.
                verbose=3,
                # project_id must be set if not running on GCP.
                # project_id='my-project-id',
            )
        except (ValueError, NotImplementedError) as exc:
            print(exc)  # Handle errors here

    您必須在 start 函式中指定 service 參數。如要在 Profiler 介面中依應用程式版本進行篩選,請指定 service_version 參數。如需疑難排解和例外狀況的相關資訊,請參閱「疑難排解」一節。

彈性環境

如果是 App Engine 彈性環境,請按照下列步驟操作:

  1. google-cloud-profiler 新增至 requirements.txt 檔案。

  2. 匯入 googlecloudprofiler 模組,並盡早在初始化程式碼中呼叫 googlecloudprofiler.start 函式。

在 App Engine 中,serviceservice_version 是衍生自您的作業環境。如需疑難排解和例外狀況的相關資訊,請參閱疑難排解一節。

標準環境

如果是 App Engine 標準環境 (您必須使用 Python 3 執行階段環境),請按照下列步驟操作:

  1. google-cloud-profiler 新增至 requirements.txt 檔案。

  2. 匯入 googlecloudprofiler 模組,並盡早在初始化程式碼中呼叫 googlecloudprofiler.start 函式。

在 App Engine 中,serviceservice_version 是衍生自您的作業環境。如需疑難排解和例外狀況的相關資訊,請參閱「疑難排解」一節。

start 個函式

googlecloudprofiler.start 函式可建立能持續收集和上傳剖析資料的 Daemon 執行緒,您應在應用程式中盡早一次呼叫 start

參數 說明
service1 (必填) 要剖析的服務名稱。如要瞭解服務名稱限制,請參閱「服務名稱和版本引數」。
service_version1 (選填) 要剖析的服務版本。服務版本相關限制請參閱「服務名稱和版本引數」。
verbose (選填) 記錄層級。如要進一步瞭解記錄層級,請參閱「代理程式記錄」。

預設值為 0 (Error)
project_id2 (選用) 您的 Google Cloud 專案 ID。
disable_cpu_profiling (選用) 如要停用 CPU 作業時間剖析功能,請設定 disable_cpu_profiling=True

這個參數支援 Python 3.2 到 3.11.0 版。其他所有 Python 版本皆無法使用 CPU 作業時間剖析功能,因而系統會忽略這個參數。

預設值為 False
disable_wall_profiling (選用) 如要停用實際時間剖析,請設定 disable_wall_profiling=True

Python 3.6 到 3.11.0 版支援這個參數。其他所有 Python 版本皆無法使用實際時間剖析功能,因而系統會忽略這個參數。

如要進一步瞭解啟用實際時間剖析功能時的 start 函式限制,請參閱「限制」一節。

預設值為 False

1 僅適用於 Compute Engine 和 GKE。如果是 App Engine,這個值將從環境衍生。
2 如果是 Google Cloud,這個值會從環境衍生;但若不是Google Cloud 環境,您就必須提供值。詳情請參閱「剖析在 Google Cloud以外環境執行的應用程式」。

分析資料

Profiler 收集資料之後,您就可以使用 Profiler 介面查看和分析資料。

前往 Google Cloud 控制台的「Profiler」頁面:

前往「Profiler」

您也可以透過搜尋列找到這個頁面。

服務名稱和版本引數

載入 Profiler 代理程式時,您可指定 service-name 引數及 service-version 引數 (選用) 來加以設定。

「service name」(服務名稱) 可讓 Profiler 收集有關這項服務的所有備用資源剖析資料。分析器服務會針對每個服務名稱的各個版本及區域組合,確保平均每分鐘一個剖析作業的收集頻率。

舉例來說,如果您有一個服務,共有兩個版本在三個區域的備用資源執行,則分析器會為這個服務建立平均每分鐘 6 個剖析作業。

如果您為備用資源使用不同的服務名稱,系統剖析服務的頻率就會比平常更高,相對地負擔也會更大。

選取服務名稱時:

  • 選擇的名稱要能清楚代表應用程式架構中的服務。如果您只執行單一服務或應用程式,服務名稱的選擇就不那麼重要;但如果應用程式是以一組微服務的形式執行,建議就應選擇適當的服務名稱。

  • 請勿在 service-name 字串中使用任何 process-specific 值 (例如 ID)。

  • service-name 字串必須符合這個規則運算式:

    ^[a-z0-9]([-a-z0-9_.]{0,253}[a-z0-9])?$

使用靜態字串 (如 imageproc-service) 做為服務名稱就是不錯的做法。

「service version」(服務版本) 則為選填項目。如果您指定服務版本,Profiler 可從多個執行個體匯總剖析資訊並正確顯示;這項引數可用來標記服務部署時的不同版本。Profiler UI 可讓您按照服務版本篩選資料,這樣一來,您就能比較新舊版程式碼的運作效能。

service-version 引數的值是任意形式的字串,不過這個引數的值看起來通常和版本號碼類似,例如 1.0.02.1.2

代理程式記錄

根據預設,剖析代理程式會記錄標記為「error」嚴重性等級的訊息。如要設定為讓代理程式記錄嚴重性等級較低的訊息,請在啟動代理程式時指定 verbose 參數。verbose 支援以下四個值:

  • 0:Error (錯誤)
  • 1:Warning (警告)
  • 2:Informational (資訊)
  • 3:Debug (偵錯)

如果您在呼叫 start 時將 verbose 參數設為 1,則系統會記錄標記為 WarningError 嚴重性等級的訊息,而 InformationalDebug 訊息將予以忽略。

如要記錄所有訊息,請在啟動代理程式時將 verbose 設為 3

googlecloudprofiler.start(service='service_name', verbose=3)

疑難排解

本節列出 Python 應用程式分析的限制、例外狀況和已知問題。如需常見問題的相關說明,請參閱疑難排解

限制

剖析資料類型 規定與限制
實際時間
  • 僅供主執行緒剖析。
  • 剖析 start 函式必須從主執行緒呼叫。
  • Profiler 訊號處理常式只能在主執行緒上執行。如果主執行緒無法執行,就無法擷取任何剖析資料。

例外狀況

錯誤 原因 解決方案
NotImplementedErrorstart 期間擲回 在非 Linux 環境中執行的應用程式。
  • 在 Linux 環境中執行應用程式。
ValueErrorstart 期間擲回 start 函式引數無效;無法從環境變數和引數判斷必要資訊;或者在 CPU 作業時間剖析和實際時間剖析功能都停用的狀態下進行剖析。
  • 確認服務名稱和版本符合服務名稱和版本引數中定義的需求。
  • 如果啟用實際時間剖析功能,請確保 start 是從主執行緒呼叫。
  • 確保您使用的是受支援的 Python 版本,並且已啟用 CPU 作業時間或實際時間剖析功能。詳情請參閱 start 函式
  • 如果您是在 Google Cloud以外的環境執行,請確認您已將 project_id 參數指定為 start。詳情請參閱 start 函式

已知問題

行為 原因 解決方案
您沒有任何設定檔資料,或是啟用了新的設定檔類型,但缺少設定檔資料。 常見原因與設定有關。 請參閱疑難排解
您使用 uWSGI,但沒有所有程序的 CPU 時間和實際時間設定檔資料。

當 uWSGI 使用多個 worker 來處理要求時,預設行為是只在主要 (「master」) 程序中執行應用程式初始化作業。分支程序不會執行初始化序列。

如果您在應用程式的初始化序列中設定剖析代理程式 (例如在 Django 應用程式的 AppConfig.ready() 中),則剖析代理程式不會針對分支程序進行設定。

如要在所有 worker 程序中執行應用程式初始化作業,請將 lazy-apps 標記設為 true

如需相關問題的解決方法,請參閱本表中的下一項主題。

您使用的是 uWSGI,且沒有實際時間剖析資料,但有 CPU 時間剖析資料。

Wall Profiler 會依附 Python 信號模組。當 Python 解譯器使用執行緒支援功能進行編譯時,預設設定會停用分支程序的自訂信號處理功能。

針對 uWSGI 應用程式,請將標記 py-call-osafterfork 設為 true,啟用自訂信號處理功能。

請參閱本表中的前一個主題,瞭解相關問題。

啟用剖析器後,錯誤記錄會包含新的項目:

BlockingIOError: [Errno 11] Resource temporarily unavailable Exception ignored when trying to write to the signal wakeup fd

GitHub 問題

您的應用程式已註冊信號喚醒檔案描述元 signal.set_wakeup_fd。根據預設,如果檔案描述元緩衝區已滿,系統會將警告記錄到 stderr。

Cloud Profiler 收集剖析資料時,會觸發高頻率信號。這種行為可能會導致檔案描述元的緩衝區變滿。

如果應用程式可以在訊號中斷時安全執行,您可以使用 Cloud Profiler。如果您使用 Python 3.7 以上版本,且想要停用警告訊息,請將 warn_on_full_buffer=False 做為參數傳遞至 signal.set_wakeup_fd

如果應用程式無法在訊號中斷時安全執行,建議您停止使用 Cloud Profiler。繼續使用可能會導致信號號碼遺失,並在錯誤記錄中產生過多項目。

使用 Linux Alpine 執行

Linux Alpine 的 Python 分析代理程式僅支援 Google Kubernetes Engine 設定。

如要建構 Python 分析代理程式,您必須安裝 build-base 套件。如要在 Alpine 上使用 Python 分析代理程式,但不想在最終 Alpine 映像檔上安裝其他依附元件,您可以使用兩階段建構作業,並在第一階段編譯 Python 分析代理程式。例如,下列 Docker 映像檔使用多階段建構功能來編譯及安裝 Python 分析代理程式:

FROM python:3.7-alpine as builder

# Install build-base to allow for compilation of the profiling agent.
RUN apk add --update --no-cache build-base

# Compile the profiling agent, generating wheels for it.
RUN pip3 wheel --wheel-dir=/tmp/wheels google-cloud-profiler

FROM python:3.7-alpine

# Copy over the directory containing wheels for the profiling agent.
COPY --from=builder /tmp/wheels /tmp/wheels

# Install the profiling agent.
RUN pip3 install --no-index --find-links=/tmp/wheels google-cloud-profiler

# Install any other required modules or dependencies, and copy an app which
# enables the profiler as described in "Enable the profiler in your
# application".
COPY ./bench.py .

# Run the application when the docker image is run, using either CMD (as is done
# here) or ENTRYPOINT.
CMD python3 -u bench.py

驗證錯誤

如果您使用的 Docker 映像檔是透過 Linux Alpine (例如 golang:alpine 或只有 alpine) 來執行,可能會看到下列驗證錯誤:

connection error: desc = "transport: authentication handshake failed: x509: failed to load system roots and no roots provided"

請注意,要查看錯誤,您必須啟用代理程式記錄功能。

以上錯誤指出,透過 Linux Alpine 執行的 Docker 映像檔根據預設並未安裝 SSL 根憑證。如果要讓剖析代理程式與 Profiler API 相互通訊,就必須具有這些憑證。如要解決這項錯誤,請在 Dockerfile 中新增下列 apk 指令:

FROM alpine
...
RUN apk add --no-cache ca-certificates

接著您必須重新建構和重新部署應用程式。

後續步驟