剖析 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 已啟用。如果未顯示,請按一下「啟用」按鈕。

將 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

在所有支援的環境中,您可以在應用程式中匯入套件,然後在應用程式中盡早初始化 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.
	}
}

在本機執行應用程式時,請設定 ProjectID (Google Cloud 專案的 ID) 和 Service 參數 (在 profiler.Config 中),因為這些值無法從本機環境衍生。您不需要設定 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 剖析功能。 在呼叫 profiler.Start 之前,先呼叫
signal.Notify(make(
chan os.Signal), syscall.SIGPROF)

GitHub 問題的回覆。

使用 Linux Alpine 執行

只有 Google Kubernetes Engine 設定支援 Linux Alpine 的 Go 分析代理程式。

驗證錯誤

如果您使用的 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

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

後續步驟