性能调优首先要对程序进行运行时分析
分析包括四个方面:
- CPU 画像:报告程序的 CPU 使用情况,按照一定频率去采集应用程序在 CPU 和寄存器上面的数据
- Memory 画像(Heap Profile):报告程序的内存使用情况
- Block 画像:报告 goroutines 不在运行状态的情况,可以用来分析和查找死锁等性能瓶颈
- Goroutine 画像:报告 goroutines 的使用情况,有哪些 goroutine,它们的调用关系是怎样的
主要关注程序运行时CPU的使用情况和内存使用情况。
画像原理:每隔一段时间(10ms)就会收集下当前的堆栈信息,获取各个函数占用的CPU以及内存资源;最后通过对这些采样数据进行分析,形成一个性能分析报告
用到两个包
runtime/pprof
:采集工具型应用运行数据进行分析(脚本型,运行一次就结束)net/http/pprof
:采集服务型应用运行时数据进行分析(服务型,一直运行提供服务)
使用pprof包得到运行时pprof文件
开启CPU性能分析:pprof.StartCPUProfile(file io.Writer) //
file, err := os.Create("./cpu.pprof")
停止CPU性能分析:pprof.StopCPUProfile()
开启内存性能分析:pprof.WriteHeapProfile(file)
分析pprof文件:
通过命令:`go tool pprof [binary] [source]
`
- binary 是应用的二进制文件,用来解析各种符号;
- source 表示 profile 数据的来源,可以是本地的文件,也可以是 http 地址。
命令示例:`go tool pprof cpu.pprof
`
执行该命令进入交互模式:输入`top 3`查看前三个函数CPU消耗情况
- flat:当前函数占用CPU的耗时
- flat::当前函数占用CPU的耗时百分比
- sun%:函数占用CPU的耗时累计百分比
- cum:当前函数加上调用当前函数的函数占用CPU的总耗时
- cum%:当前函数加上调用当前函数的函数占用CPU的总耗时百分比
还可以使用`list 函数名` 查看具体函数分析
通过图形化方式来分析CPU使用情况
安装:`brew install graphviz
`
通过火焰图进行分析:
安装go-torch工具:`go get -v github.com/uber/go-torch
` // 该工具读取 golang profiling 数据,并生成一个火焰图的 svg 文件
安装 FlameGraph工具,作用是打开并展示svg文件
- 下载安装perl:https://www.perl.org/get.html
- 下载FlameGraph:
git clone https://github.com/brendangregg/FlameGraph.git
- 将
FlameGraph
目录加入到操作系统的环境变量中。 - Windows平台的同学,需要把
go-torch/render/flamegraph.go
文件中的GenerateFlameGraph
按如下方式修改,然后在go-torch
目录下执行go install
即可。
// GenerateFlameGraph runs the flamegraph script to generate a flame graph SVG. func GenerateFlameGraph(graphInput []byte, args ...string) ([]byte, error) {
flameGraph := findInPath(flameGraphScripts)
if flameGraph == "" {
return nil, errNoPerlScript
}
if runtime.GOOS == "windows" {
return runScript("perl", append([]string{flameGraph}, args...), graphInput)
}
return runScript(flameGraph, args, graphInput)
}
压测工具:推荐使用https://github.com/wg/wrk 或 https://github.com/adjust/go-wrk
使用wrk进行压测:go-wrk -n 50000 http://127.0.0.1:8080/book/list
在上面压测进行的同时,打开另一个终端执行go-torch -u http://127.0.0.1:8080 -t 30
,30秒之后终端会初夏如下提示:Writing svg to torch.svg
然后我们使用浏览器打开torch.svg
就能看到如下火焰图了
火焰图的y轴表示cpu调用方法的先后,x轴表示在每个采样调用时间内,方法所占的时间百分比,越宽代表占据cpu时间越多。通过火焰图我们就可以更清楚的找出耗时长的函数调用,然后不断的修正代码,重新采样,不断优化。
pprof与性能测试结合
go test
命令有两个参数和 pprof 相关,它们分别指定生成的 CPU 和 Memory profiling 保存的文件:
- -cpuprofile:cpu profiling 数据要保存的文件地址
- -memprofile:memory profiling 数据要报文的文件地址
我们还可以选择将pprof与性能测试相结合,比如:
比如下面执行测试的同时,也会执行 CPU profiling,并把结果保存在 cpu.prof 文件中:
go test -bench . -cpuprofile=cpu.prof
比如下面执行测试的同时,也会执行 Mem profiling,并把结果保存在 cpu.prof 文件中:
go test -bench . -memprofile=./mem.prof
需要注意的是,Profiling 一般和性能测试一起使用,这个原因在前文也提到过,只有应用在负载高的情况下 Profiling 才有意义。