GO语言(二十三):诊断工具(上)_golang断言 判断
介绍
Go 生态系统提供了大量的 API 和工具来诊断 Go 程序中的逻辑和性能问题。
诊断解决方案可分为以下几组:
- 分析:分析工具分析 Go 程序的复杂性和成本,例如内存使用和频繁调用的函数,以识别 Go 程序的昂贵部分。
- 跟踪:跟踪是一种检测代码以分析呼叫或用户请求的整个生命周期中的延迟的方法。跟踪提供了每个组件对系统整体延迟的贡献程度的概览。跟踪可以跨越多个 Go 进程。
- 调试:调试允许我们暂停 Go 程序并检查其执行情况。程序状态和流程可以通过调试来验证。
- 运行时统计和事件:运行时统计和事件的收集和分析提供了对 Go 程序健康状况的高级概述。指标的峰值/下降有助于我们识别吞吐量、利用率和性能的变化。
注意:某些诊断工具可能会相互干扰。例如,精确的内存分析会扭曲 CPU 配置文件,而 goroutine 阻塞分析会影响调度程序跟踪。单独使用工具来获取更精确的信息。
分析
分析对于识别昂贵或经常调用的代码段很有用。Go 运行时以pprof 可视化工具所期望的格式 提供 分析数据。 可以在go test测试期间通过net/http/pprof包提供的端点或端点收集分析数据。用户需要收集分析数据并使用 pprof 工具过滤和可视化顶级代码路径。
runtime/pprof包提供的预定义配置文件:
- cpu:CPU 配置文件确定程序在主动消耗 CPU 周期时花费时间的位置(而不是在睡眠或等待 I/O 时)。
- heap:堆配置文件报告内存分配样本;用于监视当前和历史内存使用情况,并检查内存泄漏。
- threadcreate:线程创建配置文件报告导致创建新操作系统线程的程序部分。
- goroutine:Goroutine 配置文件报告所有当前 goroutine 的堆栈跟踪。
- block:块配置文件显示 goroutine 阻塞等待同步原语(包括计时器通道)的位置。默认情况下不启用阻止配置文件;用于runtime.SetBlockProfileRate启用它。
- mutex:Mutex 配置文件报告锁定争用。当您认为您的 CPU 由于互斥争用而未充分利用时,请使用此配置文件。Mutex 配置文件默认未启用,请参阅runtime.SetMutexProfileFraction启用它。
可以使用哪些其他分析器来分析 Go 程序?
在 Linux 上,性能工具 可用于分析 Go 程序。Perf 可以分析和展开 cgo/SWIG 代码和内核,因此有助于深入了解本机/内核性能瓶颈。在 macOS 上, Instruments 套件可用于配置 Go 程序。
可以用在生产服务上吗?
是的。在生产中对程序进行概要分析是安全的,但启用某些概要文件(例?如 CPU 概要文件)会增加成本。您应该会看到性能下降。性能损失可以通过在生产中打开分析器之前测量分析器的开销来估计。
您可能希望定期分析您的生产服务。尤其是在单个进程的多个副本的系统中,定期选择随机副本是一个安全的选择。选择一个生产过程,每 Y 秒对其进行 X 秒分析,并保存结果以供可视化和分析;然后定期重复。可以手动和/或自动检查结果以发现问题。配置文件的收集可能会相互干扰,因此建议一次只收集一个配置文件。
可视化分析数据的最佳方法是什么?
Go工具 使用 go tool pprof进行可视化。
Weblist 视图在 HTML 页面中逐行显示源代码的耗费资源部分。在以下示例中,每行花费了 530 毫秒,清单中 runtime.concatstrings显示了每行的成本。
另一种可视化配置文件数据的方法是火焰图。火焰图允许您在特定的祖先路径中移动,因此您可以放大/缩小特定的代码部分。
火焰图提供可视化来发现最昂贵的代码路径。
是否仅限于内置配置文件?
除了运行时提供的内容之外,Go 用户还可以通过pprof.Profile创建他们的自定义配置文件, 并使用现有工具来检查它们。
可以在不同的路径和端口上提供分析器处理程序 (/debug/pprof/...) 吗?
是的。默认情况下net/http/pprof,包将其处理程序注册到默认多路复用器,但您也可以使用从包中导出的处理程序自己注册它们。
例如,以下示例将在
/custom_debug_path/profile:7777 上为 pprof.Profile 处理程序提供服务:
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))
}
追踪
跟踪是一种检测代码以分析调用链整个生命周期中延迟的方法。Go 提供 golang.org/x/net/trace 包作为每个 Go 节点的最小跟踪后端,并提供带有简单仪表板的最小检测库。Go 还提供了一个执行跟踪器来跟踪一个时间间隔内的运行时事件。
跟踪使我们能够:
- 在 Go 进程中检测和分析应用程序延迟。
- 衡量一长串呼叫中特定呼叫的成本。
- 找出利用率和性能改进。如果没有跟踪数据,瓶颈并不总是显而易见的。
在单片系统中,从程序的构建块中收集诊断数据相对容易。所有模块都存在于一个进程中,并共享公共资源来报告日志、错误和其他诊断信息。一旦您的系统超出单个进程并开始变得分布式,就很难跟踪从前端 Web 服务器开始到其所有后端的调用,直到响应返回给用户。这就是分布式跟踪在检测和分析生产系统方面发挥重要作用的地方。
分布式跟踪是一种检测代码以分析用户请求整个生命周期中的延迟的方法。当系统是分布式的并且传统的分析和调试工具无法扩展时,您可能希望使用分布式跟踪工具来分析用户请求和 RPC 的性能。
分布式跟踪使我们能够:
- 查看大型系统中的仪器和配置文件应用程序延迟。
- 跟踪用户请求生命周期内的所有 RPC,并查??看仅在生产中可见的集成问题。
- 找出可以应用于我们系统的性能改进。很多瓶颈在收集追踪数据之前并不明显。
Go 生态系统为每个跟踪系统和后端提供各种分布式跟踪库。
有没有办法自动拦截每个函数调用并创建跟踪?
Go 没有提供自动拦截每个函数调用并创建跟踪跨度的方法。您需要手动检测代码以创建、结束和注释跨度。
我应该如何在 Go 库中传播跟踪标头?
您可以在 context.Context。业界还没有规范的跟踪密钥或跟踪标头的通用表示。每个跟踪提供者都负责在其 Go 库中提供传播实用程序。
来自标准库或运行时的其他哪些低级事件可以包含在跟踪中?
标准库正在尝试公开几个额外的 API 来通知低级别的内部事件。例如, httptrace.ClientTrace 提供 API 来跟踪传出请求生命周期中的低级事件。