Go(推送模式)
我们的 Go Profiler 是一款旨在优化 Golang 应用程序的前沿工具。通过与 Pyroscope 集成,该 profiler 为开发人员提供了对其 Go 代码库的深入视图,从而实现实时的性能分析。这款强大的工具对于查明低效率、简化代码执行以及确保 Go 应用程序的最佳性能至关重要。
Pyroscope 使用标准的 runtime/pprof
包来收集 profiling 数据。有关详细信息,请参阅官方文档。
注意
有关 Go 支持的 profile 类型列表,请参阅可用的 profiling 类型。
开始之前
要捕获和分析 profiling 数据,您需要一个托管的 Pyroscope OSS 服务器或一个托管的 带有 Grafana Cloud Profiles 的 Pyroscope 实例(需要一个免费的 Grafana Cloud 帐户)。
Pyroscope 服务器可以是用于开发的本地服务器,也可以是用于生产环境的远程服务器。
配置 Go 客户端
要开始 profiling Go 应用程序,您需要在您的应用程序中包含 Go 模块
go get github.com/grafana/pyroscope-go
注意
如果您更喜欢使用拉取模式,您可以使用 Grafana Alloy 来实现。
将以下代码添加到您的应用程序中
package main
import "github.com/grafana/pyroscope-go"
func main() {
// These 2 lines are only required if you're using mutex or block profiling
// Read the explanation below for how to set these rates:
runtime.SetMutexProfileFraction(5)
runtime.SetBlockProfileRate(5)
pyroscope.Start(pyroscope.Config{
ApplicationName: "simple.golang.app",
// replace this with the address of pyroscope server
ServerAddress: "http://pyroscope-server:4040",
// you can disable logging by setting this to nil
Logger: pyroscope.StandardLogger,
// you can provide static tags via a map:
Tags: map[string]string{"hostname": os.Getenv("HOSTNAME")},
ProfileTypes: []pyroscope.ProfileType{
// these profile types are enabled by default:
pyroscope.ProfileCPU,
pyroscope.ProfileAllocObjects,
pyroscope.ProfileAllocSpace,
pyroscope.ProfileInuseObjects,
pyroscope.ProfileInuseSpace,
// these profile types are optional:
pyroscope.ProfileGoroutines,
pyroscope.ProfileMutexCount,
pyroscope.ProfileMutexDuration,
pyroscope.ProfileBlockCount,
pyroscope.ProfileBlockDuration,
},
})
// your code goes here
}
或者,如果您想更好地控制 profiling 过程,您可以手动处理 profiler 的初始化和终止
profiler, err := pyroscope.Start(pyroscope.Config{
// omitted for brevity
})
if err != nil {
// the only reason this would fail is if the configuration is not valid
log.Fatalf("failed to start Pyroscope: %v", err)
}
defer profiler.Stop()
// your code goes here
}
如果您需要确保在应用程序退出之前发送最后一个 profile,则此方法可能是必要的。
将 profiling 标签添加到您的应用程序中
您可以将标签添加到 profiling 数据中。这些标签可用于在 UI 中过滤数据。有一个自定义 API,它与 Go 原生的 pprof API 一致
// these two ways of adding tags are equivalent:
pyroscope.TagWrapper(context.Background(), pyroscope.Labels("controller", "slow_controller"), func(c context.Context) {
slowCode()
})
pprof.Do(context.Background(), pprof.Labels("controller", "slow_controller"), func(c context.Context) {
slowCode()
})
Mutex profiling
Mutex profiling 对于查找应用程序内部的争用源非常有用。它可以帮助您找出哪些互斥锁正被哪些 goroutine 持有。
要启用互斥锁 profiling,您需要在您的应用程序中添加以下代码
runtime.SetMutexProfileFraction(rate)
rate
参数控制互斥锁争用事件在互斥锁 profile 中报告的比例。平均而言,会报告 1/rate 个事件。
Block profiling
Block profiling 让您可以分析您的程序在阻塞操作上花费了多少时间,例如
- select
- channel 发送/接收
- semacquire
- notifyListWait
要启用 block profiling,您需要在您的应用程序中添加以下代码
runtime.SetBlockProfileRate(rate)
rate
参数控制 goroutine 阻塞事件在阻塞 profile 中报告的比例。profiler 旨在对每个 rate 纳秒的阻塞时间平均采样一个阻塞事件。
将数据发送到 Pyroscope OSS 或 Grafana Cloud Profiles
要配置 Golang SDK 将数据发送到 Pyroscope,请将 <URL>
占位符替换为相应的服务器 URL。这可以是 Grafana Cloud URL 或您自己的自定义 Pyroscope 服务器 URL。
如果您需要将数据发送到 Grafana Cloud,您需要配置 HTTP 基本身份验证。将 <User>
替换为您的 Grafana Cloud 堆栈用户,并将 <Password>
替换为您的 Grafana Cloud API 密钥。
如果您的 Pyroscope 服务器启用了多租户,您需要配置租户 ID。将 <TenantID>
替换为您的 Pyroscope 租户 ID。
pyroscope.Start(pyroscope.Config{
ApplicationName: "example.golang.app",
ServerAddress: "<URL>",
// Optional HTTP Basic authentication
BasicAuthUser: "<User>",
BasicAuthPassword: "<Password>",
// Optional Pyroscope tenant ID (only needed if using multi-tenancy). Not needed for Grafana Cloud.
// TenantID: "<TenantID>",
ProfileTypes: []pyroscope.ProfileType{
pyroscope.ProfileCPU,
pyroscope.ProfileInuseObjects,
pyroscope.ProfileAllocObjects,
pyroscope.ProfileInuseSpace,
pyroscope.ProfileAllocSpace,
},
})
选项:使用 DisableGCRuns
处理增加的内存使用量
当跟踪大量对象时,Pyroscope 可能需要额外的资源。例如,索引大量数据的 Go 服务需要更多内存。这种跟踪可能会导致更高的 CPU 使用率和潜在的 CPU 限制。
您可以在 Go 配置中使用 DisableGCRuns
来禁用自动运行时。如果此标志被激活,则 GC 运行次数较少,因此 CPU 资源消耗也较少。但是,堆 profile 可能不太精确。
背景
在 Go 的 pprof 堆 profiling 中,强制垃圾回收 (GC) 通过删除未收集的对象来确保准确的内存使用快照。如果没有此步骤,堆 profile 可能包含已分配但不再使用的内存——这些对象之所以留在内存中,仅仅是因为它们尚未被收集。这可能会掩盖或模仿内存泄漏,并给 profile 引入偏差,从而使分析变得复杂。因此,Pyroscope 默认在每次收集堆 profile 时强制执行 GC。
但是,在某些情况下,强制 GC 可能会增加 CPU 使用率,尤其是在堆中有许多活动对象的情况下。此问题反映在 CPU profile 中 runtime.GC
函数的出现。如果问题已显现,并且堆 profile 中的一些不准确性是可以接受的,那么建议禁用此选项以避免性能下降。
激活 DisableGCRuns
将 DisableGCRuns: true
添加到 pyroscope.Start(pyroscope.Config)
代码块中。
pyroscope.Start(pyroscope.Config{
ApplicationName: "example.golang.app",
ServerAddress: "<URL>",
// Disable automatic runtime.GC runs between getting the heap profiles.
DisableGCRuns: true,
Golang profiling 示例
查看以下资源以了解有关 Golang profiling 的更多信息