golang中的pprof的使用,graphviz
一、关于pprof包
go中有pprof
包来做代码的性能监控,包括 cpu profile, mem profile, block profile
,在两个地方有包:
net/http/pprof
runtime/pprof
其实net/http/pprof
中只是使用runtime/pprof
包来进行封装了一下,并在http端口上暴露出来。二者的区别在于:
1、runtime/pprof
:调用了就开始采样了,数据会不断被写入文件。
2、net/http/pprof
:只有在调用了某个API的时候,才会发起采样,并sleep一段时间,时间到了就会关闭采样,所以日志文件是按需写入的。
二、使用
方法1、WEB服务器
如果你的go程序是用http包启动的web服务器,你想查看自己的web服务器的状态。这个时候就可以选择net/http/pprof
。你只需要引入包_"net/http/pprof"
,然后就可以在浏览器中使用http://localhost:port/debug/pprof/
直接看到当前web服务的状态,包括CPU占用情况和内存使用情况等。具体使用情况你可以看godoc的说明。
方法2、常驻进程
如果你的go程序不是web服务器,而是一个服务进程,那么你也可以选择使用net/http/pprof
包,同样引入包_ "net/http/pprof"
,然后在开启另外一个goroutine来开启端口监听。
比如:
go func() {
log.Println(http.ListenAndServe(":6060", nil))
}()
无论是常驻进程,还是WEb服务器场景,pprof 包都会注册如下路由
func init() {
http.HandleFunc("/debug/pprof/", Index)http.HandleFunc("/debug/pprof/cmdline", Cmdline)http.HandleFunc("/debug/pprof/profile", Profile)http.HandleFunc("/debug/pprof/symbol", Symbol)http.HandleFunc("/debug/pprof/trace", Trace)
}
如果是WEB服务器,我们可以选择监听新的端口,或者使用原有监听;但是如果使用原有监听的话可能无法注册路由,比如你使用的是GIN框架,这个时候可以使用方法2来实现;当然,GIN也有方式来以方法1来开启pprof,这个后面再讲。
访问地址:http://localhost:6060/debug/pprof/
,或者 http://localhost:6060/debug/pprof?seconds=30
点击每一项可以看到一些原始数据。
由源码可知,基于 http 的 pprof 是在你请求 profile 的时候,它会临时采集一个时间区间(比如30秒)内的对应性能数据;而访问其他指标会立即返回。再采集的时候需要来个压测,这样才会有数据。
这是一种非侵入式的指标采集,几乎不会影响服务的性能。
方法3、普通程序
如果你的go程序只是一个应用程序,比如计算fabonacci数列,由于程序的执行时间不确定,所以就不好使用net/http/pprof
包了,最好使用到runtime/pprof
来手动开启采样。具体做法就是用到pprof.StartCPUProfile
和pprof.StopCPUProfile
。比如下面的例子:
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")func main() {
flag.Parse()if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)if err != nil {
log.Fatal(err)}pprof.StartCPUProfile(f)defer pprof.StopCPUProfile()}
…
运行程序的时候加一个--cpuprofile
参数,比如./fabonacci --cpuprofile=fabonacci.prof
这样程序运行的时候的cpu信息就会记录到fabonacci.prof
中了。记录的是从 pprof.StartCPUProfile
到pprof.StopCPUProfile
这期间的CPU的累积使用情况。
由源码可知,当调用了pprof.StartCPUProfile
,就开始以每秒100次(也就是每10毫秒一次)的频率对CPU的使用情况进行采样,而pprof.StopCPUProfile
就是将采样频率设置为0且停止采样,然后等待将采样数据写入文件的过程执行完毕,因此必须要保证pprof.StopCPUProfile
被正常执行完毕,否则可能日志文件没有内容或者内容错误。
查看内存泄漏或消耗分析,可以使用
fm, err := os.OpenFile("./tmp/mem.out", os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
log.Fatal(err)
}
pprof.WriteHeapProfile(fm)
fm.Close()
三、go tool pprof 与 图形化
通过 pprof 得到的信息都是原始数据,阅读起来很费劲,我们可以通过 go tool pprof
命令来辅助查看以及图形化的方式来展示。
下载安装 graphviz :https://graphviz.org/download/
https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/2.47.3/stable_windows_10_cmake_Release_x64_graphviz-install-2.47.3-win64.exe
并且添加到环境变量。
否则会报错:
failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in %PATH%
示例:pp.gp
package mainimport ("log""net/http""fmt"_ "net/http/pprof"
)func myHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!\n")
}func main() {
http.HandleFunc("/hello", myHandler)log.Fatal(http.ListenAndServe(":6060", nil))
}
以查看CPU性能为例,先启动压测
go-wrk -c=400 -t=8 -n=100000 http://localhost:6060/hello
再输入命令
go tool pprof http://localhost:6060/debug/pprof/profile
于是进入一个交互界面
最后一列为函数名称,其他各项内容意义如下:flat: 当前函数占用CPU的时间
flat%: 当前函数占用CPU百分比
sum%: 当前所有函数累加使用 CPU 的比例
cum: 当前函数以及子函数占用CPU的时间
cum%: 当前函数以及子函数占用CPU的百分比
由提示可知,它是先将下载的原始数据保存在临时文件,然后再来分析。
常用的两个命令
top 10 列出前10
web 调用 graphviz 生成svg图片,然后打开
list 查看具体的函数分析
pdf 命令可以生成可视化的pdf文件
help 命令可以提供所有pprof支持的命令说明
当输入 web 后,会生成svg文件,会打开浏览器。
方框里面有百分比,同时方框越大占的CPU时间越多。当然,这样太难分析了,还有更直观的方式。
输入
go tool pprof http://localhost:6060/debug/pprof/profileFetching profile over HTTP from http://localhost:6060/debug/pprof/profile
Saved profile in C:\Users\Administrator.DESKTOP-TPJL4TC\pprof\pprof.samples.cpu.001.pb.gz
Type: cpu
Time: Jul 14, 2021 at 10:53am (CST)
Duration: 30s, Total samples = 23.51s (78.36%)
Entering interactive mode (type "help" for commands, "o" for options)
退出命令行,复制Saved profile
后面的文件名
go tool pprof -http localhost:3001 C:\Users\Administrator.DESKTOP-TPJL4TC\pprof\pprof.samples.cpu.001.pb.gz
这样就是在浏览器中打开了。
默认是以 greph 的方法展示,首页和上面的图形一样。
可以切换到火焰图 Flame Graph
每个方块代表一个函数,它下面一层表示这个函数会调用哪些函数,方块的大小代表了占用 CPU 使用的长短。火焰图的配色并没有特殊的意义,默认的红、黄配色是为了更像火焰而已。
另外,有时候我们通过其他途径得到了 pprof 文件,也可以通过它来分析
使用go tool pprof 应用程序 应用程序的prof文件
或者 go tool pprof prof文件
go tool pprof 教程:https://github.com/hyper0x/go_command_tutorial/blob/master/0.12.md