剖析 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.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

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

將 IAM 角色授予服務帳戶

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

如果您執行下列任一操作,則需要授予服務帳戶「Cloud Profiler 代理程式 (roles/cloudprofiler.agent)」的 IAM 角色:

  1. 您使用預設服務帳戶,但修改了角色授予。
  2. 您使用的是使用者建立的服務帳戶。
  3. 您使用 Workload Identity,請將 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 Platform 以外環境執行的應用程式 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 (偵錯)

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

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

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

疑難排解

本節列出專屬於 Python 應用程式剖析的限制、例外狀況和已知問題。如需常見問題的解決方法,請參閱疑難排解

限制

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

例外狀況

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

已知問題

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

當 uWSGI 使用多個工作人員處理要求時,預設行為只會在主要 (「主」) 程序中執行應用程式初始化。分叉程序不會執行初始化序列。

如果您在應用程式的初始化序列中設定剖析代理程式 (例如在 Django 應用程式的 AppConfig.ready() 中),剖析代理程式就不會為分叉程序設定。

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

如要瞭解相關問題,請參閱下表中的下一個主題。

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

Wall 分析器依附於 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

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

後續步驟