Go性能优化
测试代码: https://github.com/behappy-project/behappy-url-shortener
Go语言项目中的性能优化主要有以下几个方面:
- CPU profile:报告程序的 CPU 使用情况,按照一定频率去采集应用程序在 CPU 和寄存器上面的数据
- Memory Profile(Heap Profile):报告程序的内存使用情况
- Block Profiling:报告 goroutines 不在运行状态的情况,可以用来分析和查找死锁等性能瓶颈
- Goroutine Profiling:报告 goroutines 的使用情况,有哪些 goroutine,它们的调用关系是怎样的
采集性能数据
Go语言内置了获取程序的运行数据的工具,包括以下两个标准库:
runtime/pprof:采集工具型应用运行数据进行分析net/http/pprof:采集服务型应用运行时数据进行分析
pprof开启后,每隔一段时间(10ms)就会收集下当前的堆栈信息,获取各个函数占用的CPU以及内存资源;最后通过对这些采样数据进行分析,形成一个性能分析报告。
只应该在性能测试的时候才在代码中引入pprof。
工具型应用
如果应用程序是运行一段时间就结束退出类型。那么最好的办法是在应用退出的时候把 profiling 的报告保存到文件中,进行分析。对于这种情况,可以使用runtime/pprof库。 首先在代码中导入runtime/pprof工具:
1 | import "runtime/pprof" |
CPU性能分析
开启CPU性能分析:
1 | pprof.StartCPUProfile(w io.Writer) |
停止CPU性能分析:
1 | pprof.StopCPUProfile() |
应用执行结束后,就会生成一个文件,保存了我们的 CPU profiling 数据。得到采样数据之后,使用go tool pprof工具进行CPU性能分析。
内存性能优化
记录程序的堆栈信息
1 | pprof.WriteHeapProfile(w io.Writer) |
得到采样数据之后,使用go tool pprof工具进行内存性能分析。
go tool pprof默认是使用-inuse_space进行统计,还可以使用-inuse-objects查看分配对象的数量。
服务型应用
如果应用程序是一直运行的,比如 web 应用,那么可以使用net/http/pprof库,它能够在提供 HTTP 服务进行分析。
如果使用了默认的http.DefaultServeMux(通常是代码直接使用 http.ListenAndServe(“0.0.0.0:8000”, nil)),只需要在你的web server端代码中按如下方式导入net/http/pprof
1 | import _ "net/http/pprof" |
如果使用自定义的 Mux,则需要手动注册一些路由规则:
1 | r.HandleFunc("/debug/pprof/", pprof.Index) |
如果使用的是gin框架,那么推荐使用github.com/gin-contrib/pprof,在代码中通过以下命令注册pprof相关路由。
1 | pprof.Register(router) |
不管哪种方式,HTTP 服务都会多出/debug/pprof endpoint,访问它会得到类似下面的内容:
这个路径下还有几个子页面:
- /debug/pprof/profile:访问这个链接会自动进行 CPU profiling,持续 30s,并生成一个文件供下载
- /debug/pprof/heap: Memory Profiling 的路径,访问这个链接会得到一个内存 Profiling 结果的文件
- /debug/pprof/block:block Profiling 的路径
- /debug/pprof/goroutines:运行的 goroutines 列表,以及调用关系
这是一种非侵入式的指标采集,几乎不会影响服务的性能
说明其中几个endpoint
1、goroutine
点击goroutine 进入后显示当前函数栈:

2、heap
heap可以查看内存占用情况:http://127.0.0.1:xxxx/debug/pprof/heap?debug=1
看详细信息可以使用go tool pprof来进行分析:
1 | # 查看内存占用数据 |
一个函数alloc_space多不一定就代表它会导致进程的RSS高。
这个命令进入后,是一个交互式界面,输入top命令可以前10大的内存分配,flat是堆栈中当前层的inuse内存值,cum是堆栈中本层级的累计inuse内存值(包括调用的函数的inuse内存值,上面的层级)。

3、cpu
分析cpu时延:
- go tool pprof http://localhost:xxx/debug/pprof/profile

- top命令

1 | flat: 当前函数占用CPU的时间 |
- help有使用说明

- 如果输入svg 可以生成图片:

- 另外:我们输入gif,在当前目录生成一个gif图片。或者安装Graphviz后也可以输入pdf 生成pdf文件。
pprof交互命令行常用命令参数
1 | top 10 列出前10 |
go tool pprof命令
不管是工具型应用还是服务型应用,我们使用相应的pprof库获取数据之后,下一步的都要对这些数据进行分析,都可以使用go tool pprof命令行工具。
go tool pprof最简单的使用方式为:
1 | go tool pprof [binary] [source] |
或者
1 | go tool pprof prof文件 |
其中:
- binary 是应用的二进制文件,用来解析各种符号;
- source 表示 profile 数据的来源,可以是本地的文件,也可以是 http 地址。
注意事项: 获取的 Profiling 数据是动态的,要想获得有效的数据,请保证应用处于较大的负载(比如正在生成中运行的服务,或者通过其他工具模拟访问压力)。否则如果应用处于空闲状态,得到的结果可能没有任何意义。
图形化和火焰图go-torch
先安装perl
- 下载cli安装程序地址: https://platform.activestate.com/tangxing806/ActivePerl-5.28/distributions
- 安装完cli安装程序, 在cmd执行:
state activate --default tangxing806/ActivePerl-5.28 - 执行
perl --version查看成功与否
图形化工具:
下载安装 graphviz :https://graphviz.org/download/
将bin目录添加到环境变量
FlameGraph
- git clone https://github.com/brendangregg/FlameGraph.git
- 把安装目录添加到环境变量
go-torch
- go get github.com/uber/go-torch
- windows下使用需要对源码做更改, 把go-torch/render/flamegraph.go文件中的GenerateFlameGraph按如下方式修改,然后在go-torch目录下执行go install
1 | // GenerateFlameGraph runs the flamegraph script to generate a flame graph SVG. |
- 使用方式
1 | go-torch -u http://127.0.0.1:8080 -t 30 |
- 火焰图查看方式

1 | 火焰图的y轴表示cpu调用方法的先后, |
- 此外还可以借助火焰图分析内存性能数据:
1 | go-torch -inuse_space http://127.0.0.1:8080/debug/pprof/heap |
代码实验
- 我这里web框架使用的gin, 所以这里结合
gin-contrib/pprof进行测试
下载依赖: go get github.com/gin-contrib/pprof
注册相关路由: pprof.Register(g)

- 在测试接口写一段问题代码

- 访问该测试接口
会导致select语句中的default没有内容, 上面的case v:=<-c:一直执行
进入调试, 共以下几个步骤
- 调试, 查看cpu占用:
go tool pprof http://localhost:3000/debug/pprof/profile - 使用top命令查看占用排名
- 使用list方法查看该方法吃资源原因, 它会在具体问题代码处进行标记
- 通过分析发现大部分CPU资源被15行占用, 我们在default分支添加一行
time.Sleep(time.Second)即可 - 输入web, 还可以进入一个dashboard进行更详尽的信息查看
1 | PS D:\Project\study-go-project\behappy-url-shortener> go tool pprof http://localhost:3000/debug/pprof/profile |
dashboard
1 | PS D:\Project\study-go-project\behappy-url-shortener> go tool pprof -http localhost:3001 C:\Users\94391\pprof\pprof.samples.cpu.009.pb.gz |
- graph, 这个图也可以在上一步输入
svg/web进行导出svg,效果一样(如下图展示, 框越大, 则说明占用资源越多)

- source,标记了各个占用资源代码

- peek, 展示占用详尽情况

- top等同于pprof中的top
- 本质上dashboard就是交互命令行中的各个参数图形化了
speedscope UI
当然, 我们还可以用更加直观的方式分析,这里给大家推荐一个网站,https://www.speedscope.app/。 我们只需要将go tool生成的profile文件,上传到网站上:

image.png
就可以通过各种图形化的界面进行分析:

image.png