22、Go性能调优
在计算机性能调试领域里,profiling是指对应用程序的画像,画像就是应用程序使用CPU和内存的情况。Go语言是一个对性特别看重的语言,因此语言中自带了profiling的库。
Go性能优化
Go语言项目中的性能优化主要有以下几个方面:
- CPU profile:报告程序的CPU使用情况,按照一定的频率去采集应用程序在CPU和寄存器上面的数据。
- Memory Profile(Heap Profile):报告程序的内存情况。
- Block Profile:报告groutine不在运行的状况下,可以用来分析和查找死锁的性能瓶颈。
- Groutine Profile:报告goroutine的使用情况,有哪些goroutine,他们的调用关系是怎样的。
采集性能数据
Go语言内置了获取程序的运行数据的工具,包括以下两个标准库:
runtime/pprof
:采集工具型应用运行数据进行分析net/http/pprof
:采集服务型应用运行时数据进行分析
pprof开启后,每隔一段时间(10ms)就会收集当前的堆栈信息,获取个个函数占用的CPU以及内存资源,最后通过对这些采样数据进行分析,形成一个性能报告。
工具性应用
如果你的程序试运行一段时间就结束退出类型。最好的办法是在应用退出的时候把profile的报告保存到文件中,进行分析。对于这种情况,可以使用runtime/pprof
库。
1 | import "runtime/pprof" |
CPU性能分析
开启CPU性能分析:
1 | pprof.StartCPUProfile(w io.Write) |
停止CPU性能分析:
1 | pprof.StopCPUProfile() |
应用执行结束后,就生成一个文件,保存了我们的CPU profiling数据。得到采样数据后,使用go tool pprof
工具进行CPU性能分析。
内存性能优化
记录程序堆栈信息
1 | pprof.WriteHeapProfile((w io.Write) |
得到采样数据后,使用go tool pprof
工具进行性能分析。
go tool pprof
默认是使用-inuse_space
进行统计,还可以用-inuse-objects
查看分配对象的数量。
服务型应用:
如果你的程序是一直运行的,比如web应用,那么可以使用net/http/pprof
库,它能够在提供HTTP服务进行分析。
如果使用了默认的http.DefaultServeMux
(通常是代码直接使用http.ListenAndServer("0.0.0.0:8080", ni;)
),只需要在你的web server端代码中按如下方式导入net/http/pprof
1 | import _ "net/http/pprof" |
如果你使用自定义的Mux,则需要手动注册一些路由规则:
1 | r.HandelFunc("/debug/pprof", pprof.Index) |
如果使用GIN框架,推荐使用github.com/DeanThompson/ginpprof
不管什么方式,你的Http服务都会多出/debug/pprof
endpoint,访问它会得到以下内容:
这个路径下还有几个子页面:
- /debug/pprof/profile:访问这个链接会自动进行CPU profiling,持续30s,并生成一个文件提供下载
- /debug/pprof/heap:Memory Profiling的路径,访问连接会得到一个内存Profiling结果的文件
- /debug/pprof/block:block Profiling的路径
- /debug/pprof/goroutine:运行的goroutine列表,以及调用关系。
go tool pprof命令
不管是工具型应用还是服务型应用,我们使用相应的pprof库获取数据之后,下一步都要对这些数据进行分析。
1 | go tool pprof [binary] [source] |
其中:
- binary是应用的二进制文件,来解析各种符号。
- source表示profile数据的来源,可以是本地文件,也可以是http地址。
注意事项:获取的profiling数据是动态的,想要获得有效的数据,请保证应用处于较大的负载(比如正在生成中运行中的服务,或者通过其他工具模拟压力访问)。否则如果应用处于空闲状态,得到的结果可能没有任何意义。
Example:
1 | package main |
通过flag可以在命令行控制是否开启CPU和Mem的性能分析。
命令行交互界面
使用go工具链中的pprof
来分析
1 | go tool pprof cpu.pprof |
进入交互界面:
1 | 03pprof_demo>go tool pprof cpu.pprof |
使用top3
来查看程序中占用CPU前3位的函数:
1 | (pprof) top 3 |
其中:
- flat:当前函数占用cpu的耗时。
- flat%:当前函数占用cpu的耗时百分比。
- sun%:函数占用cpu放入耗时累计百分比。
- cum:当前函数加上调用当前函数的函数占用cpu的总耗时。
- cum%:当前函数加上调用当前函数的函数占用cpu的总耗时百分比。
- 最后一列:函数名称。
可以使用list 函数名
命令查看具体的函数分析。例如list logicCode
查看函数的具体分析。
1 | (pprof) list logicCode |
图形化
graphviz
go-touch和火焰图
- 安装go-touch
- 安装 FlameGraph
- 压测工具wrk:推荐使用https://github.com/wg/wrk 或 https://github.com/adjust/go-wrk
pprof与性能测试结合
go test
命令有两个参数和pprof相关,他们分别指定生成cpu和memory profiling
保存的文件:
- -cpuprofile:cpu profiling数据要保存的文件地址。
- -memprofile:memory profiling数据要保存的地址。
我们可以将pprof与性能测试相结合,比如:
执行测试的同时,也会执行CPU profiling,并把结果保存在cpu.prof文件中:
1 | go test -bench . -cpuprofile=cpu.prof |
执行测试的同时,也会执行Mem profiling,并把结果保存在mem.prof文件中:
1 | go test -bench . -memprofile=mem.prof |
Profiling一般和性能测试一起使用,只有应用在高负载的情况下profiling才有意义。