剖析 Go 應用程式

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

」。

Go 適用的剖析類型:

  • CPU 作業時間
  • 堆積
  • 分配的堆積
  • 爭用情況 (Go 互斥)
  • 執行緒 (Go goroutine)

支援的 Go 語言版本:

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

  • 支援最新版代理程式。一般來說,系統不支援發布超過一年的版本。建議您使用最新發布的代理程式版本。

支援的作業系統:

  • Linux。使用 glibcmusl 實作標準 C 程式庫的 Linux kernel 支援剖析 Go 應用程式。如需 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 已啟用),代表 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

在所有支援的環境中,您可以在應用程式中匯入套件,然後在應用程式中盡早初始化 Profiler,藉此來使用 Profiler。

MutexProfiling 設定選項設為 true,即可啟用互斥爭用情況剖析功能 (在介面中為「Contention」(爭用情況))。

如要進一步瞭解 Profiler API (包含所有設定選項),請參閱公開的 API 說明文件

Compute Engine

如果是 Compute Engine,請在 profiler.Config 中使用要剖析之服務的名稱設定 Service,並可選擇使用服務版本設定 ServiceVersion


// snippets is an example of starting cloud.google.com/go/profiler.
package main

import (
	"cloud.google.com/go/profiler"
)

func main() {
	cfg := profiler.Config{
		Service:        "myservice",
		ServiceVersion: "1.0.0",
		// ProjectID must be set if not running on GCP.
		// ProjectID: "my-project",

		// For OpenCensus users:
		// To see Profiler agent spans in APM backend,
		// set EnableOCTelemetry to true
		// EnableOCTelemetry: true,
	}

	// Profiler initialization, best done as early as possible.
	if err := profiler.Start(cfg); err != nil {
		// TODO: Handle error.
	}
}

如果您的原始碼中有手動擷取的依附元件,則可能需要將以下內容加入到建構指令碼或 Dockerfile 中:

go get cloud.google.com/go/profiler

GKE

如果是 GKE,請在 profiler.Config 中使用要剖析之服務的名稱設定 Service,並可選擇使用服務版本設定 ServiceVersion


// snippets is an example of starting cloud.google.com/go/profiler.
package main

import (
	"cloud.google.com/go/profiler"
)

func main() {
	cfg := profiler.Config{
		Service:        "myservice",
		ServiceVersion: "1.0.0",
		// ProjectID must be set if not running on GCP.
		// ProjectID: "my-project",

		// For OpenCensus users:
		// To see Profiler agent spans in APM backend,
		// set EnableOCTelemetry to true
		// EnableOCTelemetry: true,
	}

	// Profiler initialization, best done as early as possible.
	if err := profiler.Start(cfg); err != nil {
		// TODO: Handle error.
	}
}

如果您的原始碼中有手動擷取的依附元件,則可能需要將以下內容加入到建構指令碼或 Dockerfile 中:

go get cloud.google.com/go/profiler

App Engine

如果是 App Engine 彈性環境和 App Engine 標準環境,程式碼新增項目和 Compute Engine 及 GKE 的程式碼新增項目幾乎完全相同。但有一種例外情況。在上述兩個 App Engine 環境中,ServiceServiceVersion 參數都是直接衍生自環境,因此您不用另外指定。


// appengine is an example of starting cloud.google.com/go/profiler on
// App Engine.
package main

import (
	"cloud.google.com/go/profiler"
)

func main() {
	// Profiler initialization, best done as early as possible.
	if err := profiler.Start(profiler.Config{
		// Service and ServiceVersion can be automatically inferred when running
		// on App Engine.
		// ProjectID must be set if not running on GCP.
		// ProjectID: "my-project",
	}); err != nil {
		// TODO: Handle error.
	}
}

在本機執行應用程式時,請在 profiler.Config 中設定 ProjectID (Google Cloud 專案的 ID) 和 Service 參數,因為這些值無法從本機環境衍生。您不需要設定 ServiceVersion

如果您使用 App Engine 標準環境,請參閱「將您的應用程式遷移至 Go 1.11」一文,進一步瞭解需要對應用程式進行哪些變更。此外,您必須使用 Google Cloud CLI 226.0.0 以上版本。如要更新 Google Cloud CLI,請執行下列指令:

gcloud components update

執行應用程式的步驟如下:

  1. 更新依附元件。

    go get cloud.google.com/go/profiler
    
  2. 將應用程式部署到您的 App Engine 彈性環境或 App Engine 標準環境。

    gcloud app deploy [DEPLOYMENT]
    

    其中 DEPLOYMENT 是指設定檔的路徑,舉例來說,DEPLOYMENT 可能會變成 main/app.yaml

分析資料

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

代理程式記錄

剖析代理程式可在記錄檔中報告偵錯資訊。代理程式記錄功能預設為停用。

如要啟用代理程式記錄功能,請在啟動代理程式時將 DebugLogging 選項設為 true

profiler.Start(profiler.Config{..., DebugLogging: true});

疑難排解

本節列出剖析 Go 應用程式時會遇到的特定問題。 如需常見問題的解決方法,請參閱疑難排解

行為 原因 解決方案
使用 -buildmode=c-archive 建構的應用程式不會收集 CPU 時間設定檔。系統會收集堆積、爭用情況和執行緒剖析資料。GitHub 問題 如果 -buildmode 旗標為 c-archivec-shared,Go 應用程式預設不會啟用 CPU 剖析功能。 先呼叫
signal.Notify(make(
chan os.Signal), syscall.SIGPROF)
再呼叫 profiler.Start
GitHub 問題的回覆。

使用 Linux Alpine 執行

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

驗證錯誤

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

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

請注意,要啟用代理程式記錄功能才能看到錯誤。 根據預設,Go 的代理程式不會輸出任何記錄訊息。

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

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

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

後續步驟