golang深度学习-性能分析
性能分析
Go语言原生支持在运行时保留重要的特征指标和状态,有许多工具可以分析甚至可视化程序运行的状态和过程。
- pprof工具:常用于分析资源的使用情况,可以采集程序运行时的多种不同类型的数据(例如CPU占用、内存消耗和协程数量等),并对数据进行分析聚合生成的报告。
- trace工具:则关注程序运行时的事件(例如协程状态切换,GC的开始和结束、系统调用等等),常用于分析延迟、阻塞和调度等问题。
pprof工具
Go语言中的pprof指对于指标或特征的分析(Profiling),通过分析不仅可以查找到程序中的错误(内存泄漏、race冲突、协程泄漏),也能对程序进行优化(例如CPU利用率不足)。pprof使用主要有两种方式,一种是在项目中导入runtime/pprof
,另一种是导入net/http/pprof
包。
- runtime/pprof:
runtime/pprof
提供各种相对底层的API用于生成采样数据,可以调用 runtime.StartCPUProfile 或者 runtime.StopCPUProfile 等API来生成和写入采样文件,灵活性高。 - net/http/pprof:通过http服务获取Profile采样文件,简单易用,适用于对应用程序的整体监控。本质上
net/http/pprof
是对runtime/pprof
的包装,并通过 http 的方式向外部暴露数据。相关的API接口如下:- /debug/pprof/profile:获取 CPU 的抽样信息
- /debug/pprof/heap:当前活动对象内存分配的抽样(也就是堆栈内存)
- /debug/pprof/goroutine:获取 goroutine 的执行堆栈
- /debug/pprof/trace:获取当前程序执行的轨迹(获取 GMP 以及 goroutine的调度信息)
- /debug/pprof/block :获取导致同步阻塞的堆栈(特定场景使用,如:延迟高但CPU内存无明显变化、要求高并发、高QPS)
- /debug/pprof/mutex:获取互斥锁的持有者(特定场景使用,如:延迟高但CPU内存无明显变化、要求高并发、高QPS)
- /debug/pprof/threadcreate:获取创建的线程信息(内核态线程)
- /debug/pprof/cmdline:获取当前运行程序的启动参数
- /debug/pprof/allocs : 获取内存分配的抽样数据(不常用,因为heap中已包含此信息)
数据采集
通过 net/http/pprof
暴露的端点进行下载,如:trace、profile、goroutine stack dump。
通过 go tool pprof
工具指定采样的时间转储到文件中再分析。如:
- profile:CPU时间。
go tool pprof http://<IP>:<PORT>/debug/pprof/profile?seconds=30
- allocs/heap:内存分配
go tool pprof http://<IP>:<PORT>/debug/pprof/heap?seconds=30
- goroutine:协程使用情况
go tool pprof http://<IP>:<PORT>/debug/pprof/goroutine?seconds=30
- 转储到指定文件中在分析
curl -o cpuprofile.out http:<IP>:<PORT>/debug/pprof/profile
go tool pprof -http=:<PORT> cpuprofile.out
通过编码直接生成或启动单元测试。如:
// CPU
f, _ := os.Create("cpuprofile.out")
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
// 堆内存
fp, _ := os.Create("heapprofile.out")
pprof.WriteHeapProfile(fp)
// go test生成
go test -run=<TEST_UNIT> -memprofile memprofile.out -cpuprofile cpuprofile.out
Go程序运行中,随机选择一个处于正在执行状态的协程,记录该协程当前的调用栈。采样频次越高采样的结果就越逼近真实结果。开启pprof采样后,(CPU和堆内存)对性能有影响但是非常小(协程栈影响较大,需要StopTheWorld),生产环境可以放心使用。
分析模式
常用的分析模式有:
- svg矢量图:适合从整体上对资源使用情况进行把握,并且还可以辅助分析程序的调用链情况。
- 火焰图:适合查看函数调用耗时的场景。横条越长,资源消耗、占用越多。
- top 按占比由大到小排序:flat、flat%表示当前函数本身的汇总、占比;sum%表示上方所有行的flat%累加值;cum、cum%表示函数总体(本身+下游调用)的汇总和占比。
- source 源代码分析:对函数内部逐行深入分析,一般需要配合搜索框一起使用。
- peek 调用上下游分析:量化的分析上下游调用的占比情况。可以分析出代码中某些函数的调用是否合理。
堆内存分析的关键指标
- alloc_objects:堆中存在的对象数量(包括存活和非存活对象)
- alloc_space:堆中存在的对象所占用内存的大小
- inuse_objects:堆中正在使用的对象的数(只包含存活对象)
- inuse_space:整个堆内存大小
协程栈分析:查看协程的数量是否存在协程泄露;查看协程正在执行的函数确认协程是否健康。
高德Go生态的服务稳定性建设|性能优化的实战总结
Golang性能分析工具从原理到实战
郑建勋:Go程序性能分层优化 | CPU篇