Preface

在性能分析方面, golang提供了 pprof 工具, 帮助定位 内存、cpu、goroutine 的问题. pprof提供的功能在 runtime/pprof 的包中, 也提供了 http的接口, 参考 net/http/pprof

Tools

总入口

pprof的总的入口是 http://$host:$port/debug/pprof, 内存 cpu mutex 和 block 的检测都是在 这个入口的分类

goroutine

goroutine 的入口是 http://$host:$port/debug/pprof/goroutine?debug=1, 一般需要对比两个不同时段的 goroutine 数量来判断增量 是否合理

goroutine 还支持 debug参数, 默认为0: 函数地址需要 pprof 还能解读, 还原函数名字; debug=1 可以在浏览器中查看; debug=2 unrecovered panic 的格式打印堆栈,可读性更高.

内存

内存的常规入口: go tool pprof -inuse_space http://$host:$port/debug/pprof/heap, 这个命令有一个特别的参数 -inuse_space, 表示采样的对象是 正在使用的内存空间, 除此之外, 还有 -inuse_objects-alloc_space-alloc_objects. 如果是内存泄露, 可以根据 inuse_space 的占比和变化判断, 但是 也不是万能的, 有些时候, 一些 inuse_space 是因为高流量导致的. 对于 频繁创建的一些对象 可以在 alloc_spacealloc_object 判断, 这种场景可以通过 复用对象池 来减少没意义的分配.

cpu

cpu 的常规入口: go tool pprof http://$host:$port/debug/pprof/profile, 一般很少直接使用, 都是配合火焰图一起使用, 使用如下: go tool pprof -http :9090 http://$host:$port/debug/pprof/profile, 在展示的时候可以使用 flame graph 选项.

block profile

可以观察每个goroutine的情况, 堵塞、系统调用等统计, block profile 需要显示打开, 如下:

runtime.SetBlockProfileRate(100 * 1000 * 1000) // 100ms的block监控

通过 pprof界面上的 block profile 跳转过去. golang 程序中很多会使用无锁channel进行同步 以及 底层网络fd监控, 会出现block profile数据

mutex profile

可以观察程序锁的情况:

runtime.SetMutexProfileFraction(100 * 1000 * 1000) // 100ms的锁耗时监控

通过 pprof界面上的 mutex profile 跳转过去. 正常情况下不会出现 mutex profile 的数据, 出现了都需要重点解决下

参考: https://talks.golang.org/2017/state-of-go.slide#23

其他的小技巧

  1. 有时候我们希望指定采样的时候, 可以在 http的请求参数后面添加: ?seconds=60, 或者在命令参数中指定 --seconds 25 , 比如cpu采样: go tool pprof --seconds 25 http://localhost:9090/debug/pprof/profile
  2. 纯粹的命令行展示经常对观察不太友好, 我们需要http 这种可以火焰图可视化的辅助, 命令参数中需要添加 -http :9090, 比如内存的可视化: go tool pprof -http :9090 http://$host:$port/debug/pprof/heap
  3. 命令行常用指令:
- top N: 查看排名前N个的函数
- web: 生成svg, 进入web页面展示
- list funcname: 显示函数信息
- top 20 -cum: 累计的top (会叠加被调用函数的统计维度, 比如cpu不仅仅是当前函数, 还包括调用的其他函数的计时, 通过cum进行排序)
  1. 分析cpu看到有问题的函数名的时候, 我们希望看到对应的代码, 这种就需要指定代码路径和调用栈了, 比如这样: go tool pprof -call_tree -source_path ~/go/pkg/mod http://localhost:9301/debug/pprof/profile

  2. 火焰图除了使用pprof 的http, 也可以使用 go-torch 生成, 比如 go-torch -u http://$host:$port -t 30, 运行命令后会生成一个 svg 图片, 然后点击打开就可以了

  3. 占用cpu/mem 多, 并不一定有问题, 很有可能是高流量导致的, 如果无法sync.pool复用, 可以忽略掉

trace

可以观察每个p、g的情况, 使用如下

curl -o trace.out http://localhost:8000/debug/pprof/trace?seconds=15 
go tool trace trace.out

参考文档: https://colobu.com/2019/05/22/profilinggo/ 可以查看每个p的情况

gc 优化:

开启gc追踪, 怎么用?

GODEBUG=gctrace=1

gctrace? go build –gcflags=-m libs/httpclient/httpclient.go

逃逸分析

https://cloud.tencent.com/developer/article/1165854

常见的detection:

  • goroutine 跑飞了
  • heap跑飞了
  • cpu利用率过高

更新

官方有相关文档的介绍: https://github.com/golang/go/wiki/Performance

补充

有时候分析问题, 可以使用转储文件, 如下:

gcore $pid
dlv core ./二进制 core.$pid

参考

  1. runtime/pprof
  2. google官方文档
  3. google官方工具
  4. profiling官方文档
  5. gperftool工具
  6. 官方pprof示例使用blog
  7. frame graph