前言,发现一直没有记录过 pprof 分析的博客,其实在实际的业务场景中已经使用它很多次了,对于性能分析来说它真的是一大杀器,基本上有了它,80% 的性能问题都能被一目了然。每次出现性能问题,总是下面几个步骤,测试环境开 pprof,启动,流量重放,火焰图生成,一看,仔细分析一下,问题就浮于水面。

今天来用最简单的一个案例,来让你快速上手 pprof,所以本博客包含以下内容

  • 最快能让你用上 pprof
  • 能让你最快学会认识火焰图
  • 学会了之后其他剩下的功能你就可以慢慢自己摸索了

废话不多直接上案例

前期准备

首先你肯定有 go 环境,需要看火焰图还需要安装 graphviz http://www.graphviz.org/download/

第一个坑来了,如果 mac 使用 brew install graphviz 安装容易出现失败,还有很多奇怪的依赖如 svn java 等,所以建议使用 sudo port install graphviz 安装

问题发现

image-20210724163218760

使用一些监控软件发现问题,如当前我发现有一个项目在刚启动之后,其他相同类似的项目 cpu 使用都是 20 多,但是它有 40 多(虽然很少了,但是相较于其他先相同服务来说太多了)想知道为什么,所以想来分析一下。

pprof 代码使用

pprof 需要你再代码里面主动声明开启

没有使用 web 框架的项目

如果你的项目没有使用任何 web 框架的话,可以使用如下方式开启

1
2
3
4
5
6
import (
_ "net/http/pprof"
)

// 代码中加入
http.ListenAndServe(":8080", nil)

pprof 包中有 init 函数,会主动注册相关路由,只要你监听对应一个端口,则可以使用了

访问 : http://127.0.01:8080/debug/pprof/

使用 web 框架的项目

因为你的项目使用了 web 框架,所以默认的引入方式没办法注册到你自己创建的路由上,所以需要使用一些特殊手段,这里以 gin 框架举例

1
2
3
4
5
6
7
import (
"github.com/gin-contrib/pprof"
)

// 代码中加入
r := gin.New()
pprof.Register(r)

其实里面的代码也很简单,就是将 pprof 暴露的 handler 包装了一下,将对应的路由注册上就可以,其他相关的 web 框架也应该都有类似的方案

基本信息

image-20210724163815236

首先你查看之后会有这样一个页面,上面的一些基本信息你就能看到了,最长使用的就是 goroutine 和 heap 了,能很好的看到每个 goroutine 在干嘛,堆里面有哪些东西等等。

pporf 命令行使用

这里没有什么花里胡哨的各种命令,直接说最简单最常使用的火焰图(还有 top 等其他命令可以查看对应文档学习)

go tool pprof http://127.0.0.1:8080/debug/pprof/profile

然后耐心等待 30s 左右会生成对应的 cpu 使用采样文件

Fetching profile over HTTP from http://127.0.0.1:8080/debug/pprof/profile
Saved profile in /Users/linkinstar/pprof/pprof.orders.samples.cpu.001.pb.gz

如果相关分析的是内存而不是 cpu 则需要将地址 http://127.0.0.1:8080/debug/pprof/profile 修改为 -> http://127.0.0.1:8080/debug/pprof/heap

会弹出一个命令行交互程序输入 help 可以查看相关命令

新开一个命令行窗口:

go tool pprof -http=:8081 /Users/linkinstar/pprof/pprof.orders.samples.cpu.001.pb.gz

后面的路径为上面生成的采样文件的路径

然后你就能到一个 web 界面了

Ps: 当然你也可以将两个命令合成为一个命令进行使用,如 go tool pprof -http=:8081 127.0.0.1:8080/debug/pprof/heap

火焰图如何看

image-20210724164906547

首先从 view 中选择 flame graph

然后你就能看到火焰图了,一开始看可能会有点懵,不要紧,告诉你三点,然后就很简单了:

  1. 看横轴最长的:横着占用最长的,就是 cpu 占用最多的(如果你看的是内存,则是内存占用最多的)
  2. 看纵轴最长的:纵轴表示的是函数调用栈,从上到下就是函数 a 调用函数 b 调用函数 c… 纵轴越长调用栈越长
  3. 鼠标移到对应横轴最长的,然后点击,即可慢慢继续分析了

当前案例分析

image-20210724164932166

当前我们看到这个生成的火焰图中横轴最长的就是 resolveServiceFromConsul 方法

显然就是这个方法占用了很多 cpu 资源,那么就很清楚了,去代码里面看,这个方法在干什么,原来是 consul 和各个注册微服务的消息交互导致。问题不大。

对比图分析

可以通过 –base 参数对比两个采样数据 tool pprof -http=:9999 --base ./heap.1 heap.2

常用 pprof 命令总结

下面是干货分享,总结了一些最常用的 pprof 的命令如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 下载 cpu profile 默认从当前开始收集30s的cρu使用情况, 需要等待3θs
go tool pprof http://127.0.0.1:8080/debug/profile

# wait 120s
go tool pprof http://127.0.0.1:8080/debug/pprof/profile?seconds=120

# 下载 heap profile
go tool pprof http://127.0.0.1:8080/debug/pprof/heap

# 下载特定类型的heap
go tool pprof -sample_index=alloc_space http://127.0.0.1:8080/debug/pprof/heap
go tool pprof --inuse_objects http://127.0.0.1:8080/debug/pprof/heap

# 比较base
go tool pprof -base pprof.demo.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz pprof.demo.alloc_objects.alloc_ space.inuse_objects.inuse_space.002.pb.gz

# 下载 goroutine profile
go tool pprof http://127.0.0.1:8080/debug/pprof/goroutine

# 下载 block profile
go tool pprof http://127.0.0.1:8080/debug/pprof/block

# 下载 mutex profile
go tool pprof http://127.0.0.1:8080/debug/pprof/mutex

# 在浏览器里交互
go tool pprof --http=:8080 ~/Downloads/LinkinStar/profile

总结

pprof 还有很多其他功能,这里是最快的入门方式,让你快速能领略这个工具分析的方法,使用其实非常简单,不过显然实际出现问题没有那么简单,有时候经常会出现 cpu 占用最多的是 runtime 的代码,或者有一些内存泄露的分析需要细细排查原因,如果你没有用起来的话,赶紧上吧!