剖析 Go 应用的性能

本页介绍了如何修改 Go 应用以捕获性能分析数据,并将这些数据发送到您的 Google Cloud项目。如需了解性能剖析的常规信息,请参阅性能剖析相关概念

Go 的性能剖析文件类型:

  • CPU 时间
  • 分配的堆
  • 争用 (Go mutex)
  • 线程 (Go goroutine)

支持的 Go 语言版本:

  • 除非另有说明,否则所有已正式维护的 Go 版本。 如需了解详情,请参阅 Go 语言发布政策

支持的性能剖析代理版本:

  • 支持代理的最新版本。通常,不支持发布超过一年的版本。我们建议您使用最近发布的代理版本。

支持的操作系统:

  • Linux。Linux 内核支持剖析 Go 应用的性能,其标准 C 库是使用 glibcmusl 实现的。如需了解针对 Linux Alpine 内核的特定配置信息,请参阅在 Linux Alpine 上运行

支持的环境:

启用 Profiler API

在使用性能剖析代理之前,请确保已启用底层 Profiler API。您可以使用 Google Cloud CLI 或 Google Cloud 控制台查看该 API 的状态以及在必要时启用该 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 已启用,则表示此 API 已经启用。如未显示,请点击启用按钮。

向服务账号授予 IAM 角色

如果您要在资源上部署应用,并且使用的是默认服务账号,并且未修改向该服务账号授予的角色,则可以跳过本部分。 Google Cloud

如果您执行以下任何操作,则需要向服务账号授予 Cloud Profiler Agent (roles/cloudprofiler.agent) IAM 角色:

  1. 您使用的是默认服务账号,但修改了其角色授予。
  2. 您使用的是用户创建的服务账号。
  3. 如果您使用的是 Workload Identity,请向 Kubernetes 服务账号授予 Cloud Profiler Agent 角色。

您可以使用 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 即可启用互斥争用性能剖析(界面中的“争用”)。

如需详细了解 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 可以收集该服务所有副本的性能剖析数据。对于每个组合服务版本和区域中的每个服务名称,Profiler 服务将保证平均每分钟生成一个性能剖析文件的收集速率。

例如,如果您的服务有两个版本在三个区域中的副本上运行,那么 Profiler 平均每分钟将为该服务创建 6 个性能剖析文件。

如果您为副本使用不同的服务名称,那么对服务执行性能剖析的频率将超出必要频率,相应的开销也会更高。

选择服务名称时,应注意以下几点:

  • 选择的名称应能清楚地表示应用架构中的服务。如果您只运行单个服务或应用,那么服务名称的选择没那么重要;但如果您的应用作为一组微服务运行,则服务名称的选择较为重要。

  • 切勿在服务名称字符串中使用任何进程专用的值,例如进程 ID。

  • 服务名称字符串必须与如下正则表达式相符:

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

建议使用 imageproc-service 这样的静态字符串作为服务名称。

服务版本是可选的。如果您指定服务版本,则 Profiler 可以汇总来自多个实例的性能剖析信息并将其正确显示出来。服务版本可用于在部署服务时标记不同的版本。Profiler 界面支持您按服务版本过滤数据,这样一来,您就可以比较新旧版本代码的性能。

服务版本参数的值是一个使用自由格式的字符串,但此参数的值通常看起来像版本号,例如 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 运行

只有 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 根证书。这些证书为性能剖析代理与性能剖析器 API 进行通信所必需。如需解决此错误,请将以下 apk 命令添加到您的 Dockerfile 中:

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

然后,您需要重新构建并重新部署应用。

后续步骤