Introduction
Go生态系统提供了大量API和工具来诊断Go程序中的逻辑和性能问题。 此页面总结了可用的工具,并帮助Go用户针对他们的特定问题选择正确的工具。
诊断解决方案可分为以下几组:
- Profiling:Profiling 工具分析Go程序的复杂性和成本,例如其内存使用情况和频繁调用的函数,以识别Go程序的昂贵部分。
- Tracing:Tracing 是一种检测代码的方法,用于分析调用或用户请求的整个生命周期中的延迟。 Traces 提供了每个组件对系统总体延迟影响的概览。 Traces 可以跨越多个Go进程。
- Debugging: Debugging 允许我们暂停Go程序并检查其执行。可以通过 debugging 验证程序状态和流程。
- Runtime statistics and events: 对运行时统计信息、事件的收集和分析提供了Go程序运行状况的高层次概览。 指标的尖峰/下降有助于我们识别吞吐量,利用率和性能的变化。
注意:某些诊断工具可能会相互干扰。 例如,精确的 memory profiling 会扭曲 CPU profiles,而goroutine blocking profiling 会影响 scheduler trace。 隔离使用工具可获得更精确的信息。
Profiling
Profiling 对于识别昂贵或经常调用的代码段很有用。 Go runtime 以 pprof 可视化工具所期望的格式提供 profiling data。 在测试期间可以通过 go test
或 net/http/pprof 包提供的 endpoints 收集 profiling data。 用户需要收集 profiling data 并使用 pprof 工具来过滤和可视化顶部代码路径。
runtime/pprof 包提供的预定义 profiles:
- cpu: CPU profile 确定程序在活跃的消耗CPU周期(而不是在睡眠或等待I/O时)花费时间的位置。
- heap: Heap profile 报告内存分配样本; 用于监视当前和历史内存使用情况,并检查内存泄漏。
- threadcreate: Thread creation profile 报告程序中导致创建新OS线程的部分。
- goroutine: Goroutine profile 报告所有当前 goroutines 的 stack traces。
- block: Block profile 显示goroutine阻止等待同步原语(包括 timer channels)的位置。 Block profile 默认情况下未开启; 使用
runtime.SetBlockProfileRate
启用。 - mutex: Mutex profile 报告锁竞争。 如果您认为由于互斥竞争而未充分利用您的CPU,请使用此 profile。 Mutex profile 默认情况下未开启,请参阅
runtime.SetMutexProfileFraction
启用。
我可以使用其他哪些 profilers 来介绍Go程序?
在Linux上,perf tools 可用于分析Go程序。 Perf 可以 profile 和展开 cgo/SWIG 代码和内核,因此深入了解native/内核性能瓶颈非常有用。 在macOS上, Instruments 套件可以用来 profile Go 程序。
我可以 profile 我的生产环境的服务吗?
是的。 在生产环境中对程序进行 profile 是安全的,但启用某些 profiles(例如:CPU profile)会增加消耗。 您应该会看到性能降级。 在生产中打开探测器之前,可以通过测量 profiler 的开销来估计性能损失。
您可能希望定期分析您的生产服务。 特别是在具有单进程多副本的系统中,定期选择随机副本是安全的选择。 选择一个生产服务, 每隔Y秒 profile X秒并保存结果以进行可视化和分析; 然后定期重复。 可以 手动/自动 检查结果以发现问题。 profiles 收集可能会相互干扰,因此建议一次只收集一个 profile。
可视化分析数据的最佳方法是什么?
Go tools使用 go tool pprof
提供文本,图形和 callgrind 可视化的 profile data。 阅读 Profiling Go programs 以查看它们的实际使用。
文本方式查看最大的消耗的调用
图片方式可视化最大的消耗的调用
Weblist视图在HTML页面中逐行显示源代码最大消耗的部分。 在以下示例中,530ms用于 runtime.concatstrings
,每行的消耗显示在列表中。
weblist方式可视化最大的消耗的调用
另一种可视化轮廓数据的方法是火焰图。 火焰图允许您在特定的祖先路径中移动,因此您可以放大/缩小特定的代码段。upstream pprof支持火焰图。
火焰图方式可视化以发现最昂贵的代码路径
我是否仅限于内置profiles?
除了 runtime 提供的工具之外,Go用户还可以通过 pprof.Profile 创建自定义 profiles,并使用现有工具对其进行检查。
我可以在不同的路径和端口上提供 profiler handlers(/debug/pprof/…) 吗?
是的。 默认情况下, net/http/pprof
包将其 handlers 注册到默认的mux,但您也可以使用从包中导出的handler net/http/pprof注册它们。
例如,以下示例将在7777端口/custom_debug_path/profile上提供 pprof.Profile handler:
package main import ( "log" "net/http" "net/http/pprof" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/custom_debug_path/profile", pprof.Profile) log.Fatal(http.ListenAndServe(":7777", mux)) }