Go语言原生支持对于程序运行时重要指标和特征的分析,以及事件的追踪。
pprof工具可实现对于指标和特征的分析,通过分析可以查找到程序中的错误,比如内存泄露,race冲突,协程泄漏,cpu利用率过高等;也可以对程序进行优化。
trace工具是以事件为基础的信息追踪,可反映一段时间内程序的变化,比如频繁的gc及协程调度等。
在生产环境中,由于go语言运行时的指标不对外暴露,需要通过一系列工具分析查询。而且在很多情形下,我们往往也不会直接通过http接口调用的方式在生产环境中直接分析特征文件,需要将特征文件取样下载到本地之后再解析分析。
01
—
关于pprof
pprof是谷歌推出的golang可视化和分析数据的工具,该工具在golang安装时即存在:https://github.com/google/pprof/blob/main/doc/README.md
pprof 读取 profile.proto 格式的分析样本集合并生成报告以可视化和帮助分析数据,生成文本和图形报告。pprof提供的功能在 runtime/pprof 的包中, 也提供了 http的接口, 参考 net/http/pprof。
pprof的总的入口是http://host:port/debug/pprof , 内存, cpu, mutex 和 block 的检测都是在这个入口的分类。
#堆内存特征分析
在容器里获取特征文件:
curl -o heap.out http://localhost:{port}/debug/pprof/heap
下载到本地后用pprof工具分析
go tool pprof heap.out
当执行pprof分析堆内存的特征文件时,默认的类型为inner_space,代表分析程序正在使用的内存。
全部支持的类型如下:
inuse_space: 正在使用的内存大小
inuse_objects: 正在使用,尚未被释放的对象数量
alloc_space: 已经被分配的内存空间,没有考虑对象释放的情况
alloc_objects: 已经被分配的对象数量,没有考虑对象释放的情况
如果是内存泄露, 可以根据 inner_space 的占比和变化判断, 但是也不是万能的, 有些时候, 一些 inuse_space 是因为高流量导致的. 对于频繁创建的一些对象 可以在 alloc_space和 alloc_object 判断, 这种场景可以通过复用对象池来减少没意义的分配。
下面介绍一些常用的指令:
top会列出默认以flat列排序的序列:
flat指当前函数统计的值,比如在inner_space模式下,则代表当前函数分配的正在使用的堆内存大小。
cum指当前函数及其调用的一系列的flat的和。
flat只包含当前函数的栈帧信息,不包括其调用的函数的栈帧信息。
如果切到了alloc_objects模式,所以表示分配对象的次数。
通过指定-cum参数,top指令可以通过对比得到大致的问题函数调用关系:
通过list指令可以找出函数具体内存/对象分配发生在哪一行。
通过tree指令可以打印函数的调用链,能够得到具体函数的调用堆栈信息。
以上可以看出,teenagersUpdate函数频繁的创建出一些对象,其调用和占总分配次数的30%左右,并可以看出在调用栈的哪里可能有问题。
在pprof交互行中输入help,可以看到更多指令和使用方法:
#CPU分析
在容器里获取特征文件:
curl -o profile.out http://localhost:{port}/debug/pprof/profile
有时候我们希望指定采样的时候, 可以在 http的请求参数后面添加: ?seconds=60
下载到本地后用pprof工具分析
go tool pprof profile.out
和堆内存同样的指令,分析cpu文件:
top20可以看占用cpu的前20位函数,tree可以打出调用栈
cpu和内存的情况都可以搭配火焰图一起看。
#其它可以通过pprof分析的场景
pprof协程栈分析:
go tool pprof http://localhost:{port}/debug/pprof/goroutine
base基准分析:
go tool pprof -base pprof.goroutine.001.pb.gz pprof.goroutine.002.pb.gz
mutext堵塞分析
go tool pprof http://localhost:{port}/debug/pprof/mutex
#火焰图和性能图
火焰图
从Go11之后,火焰图已经内置到pprof分析工具中,用于分析堆内存和cpu的使用情况,分析要点:
1.最下方的root代表程序的开始,其它的框都代表一个函数
2.火焰图每一层中的函数都是平级的,下层函数是其对应的上层函数的字函数。
3.函数调用栈越长,火焰就越高
4.框越长,颜色越深,代表当前函数占用内存越多
5.可以单击任何框,查看该函数更详细的信息
性能图
关于节点的说明:
红色节点代表当前cum值很大,灰色节点代表当前cum值很小
节点里较大的字体表示较大的当前值,较小的字体表示较小当前值
关于箭头的说明:
箭头越粗代表当前的路径消耗了越多的资源,箭头越细代表当前的路径消耗越少的资源。
虚线箭头表示两个节点间的某些节点已被忽略,为间接调用;实线箭头表示两个节点之间为直接调用。
curl -o trace.out http://localhost:{port}/debug/pprof/trace?seconds=30s
go tool trace trace.out
选中其中一个goroutine可以看到针对该go routine的view trace信息可视化界面:
在view trace链接跳转的界面可以追溯该goroutine出现的上下文,究竟发生了什么:
界面的几个信息说明:
title:协程名字
start:协程开始的时间
wall duration:协程持续时间
start stack trace:协程开始时的栈追踪
end stack trace:协程结束时的栈追踪
event:协程产生的事件信息
同时也可以通过view trace界面分析gc的次数以及异常情况。