Gin框架中使用pprof进行性能观测

在实际业务中需要保证业务的性能及稳定性,而通过类似Postman这样的API测试工具,通常只在研发自测阶段验证API是否可用。面对并发场景时,一般会使用wrk或者JMeter等工具进行压测,摸底业务当前的性能指标和稳定性情况,那么在使用Gin框架编写的业务中,一般是使用pprof来观察性能损耗,这里就记录下怎么使用。

pprof介绍

关于pprof,golang标准库自带性能分析工具,需要在代码中手动添加相应的分析代码来收集性能数据。比如runtime/pprof和net/http/pprof,开启pprof后,提供了对程序运行时各种性能指标(如 CPU、内存、锁等)的详细分析能力。

对于Gin框架的pprof来说,我们可以直接使用这个项目:https://github.com/gin-contrib/pprof

其对net/http/pprof做了封装,使用方式非常简单,直接pprof.Register(router)即可。当开启pprof时,启动程序后,可以看到如下的路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET /debug/pprof/ --> github.com/gin-contrib/pprof.RouteRegister.WrapF.func1 (3 handlers)
[GIN-debug] GET /debug/pprof/cmdline --> github.com/gin-contrib/pprof.RouteRegister.WrapF.func2 (3 handlers)
[GIN-debug] GET /debug/pprof/profile --> github.com/gin-contrib/pprof.RouteRegister.WrapF.func3 (3 handlers)
[GIN-debug] POST /debug/pprof/symbol --> github.com/gin-contrib/pprof.RouteRegister.WrapF.func4 (3 handlers)
[GIN-debug] GET /debug/pprof/symbol --> github.com/gin-contrib/pprof.RouteRegister.WrapF.func5 (3 handlers)
[GIN-debug] GET /debug/pprof/trace --> github.com/gin-contrib/pprof.RouteRegister.WrapF.func6 (3 handlers)
[GIN-debug] GET /debug/pprof/allocs --> github.com/gin-contrib/pprof.RouteRegister.WrapH.func7 (3 handlers)
[GIN-debug] GET /debug/pprof/block --> github.com/gin-contrib/pprof.RouteRegister.WrapH.func8 (3 handlers)
[GIN-debug] GET /debug/pprof/goroutine --> github.com/gin-contrib/pprof.RouteRegister.WrapH.func9 (3 handlers)
[GIN-debug] GET /debug/pprof/heap --> github.com/gin-contrib/pprof.RouteRegister.WrapH.func10 (3 handlers)
[GIN-debug] GET /debug/pprof/mutex --> github.com/gin-contrib/pprof.RouteRegister.WrapH.func11 (3 handlers)
[GIN-debug] GET /debug/pprof/threadcreate --> github.com/gin-contrib/pprof.RouteRegister.WrapH.func12 (3 handlers)

其中,这些分析指标对应的含义是:
cmdline:当前程序的命令行的完整调用路径。
profile:进行CPU分析,可以通过GET请求参数指定时间范围。
symbol:会查找请求中列出的程序计数器,并提供程序计数器与函数名称的映射表。
trace:生成对目前程序执行的分析文件,用于通过go tool trace进行分析,可以通过GET请求参数指定时间范围。
allocs:查看过去所有的内存分配信息。
block:查看导致阻塞同步的堆栈跟踪。
goroutine:查看当前所有运行的goroutines堆栈跟踪。
heap:查看活动对象的内存分配情况。
mutex:查看导致互斥锁的竞争持有者的堆栈跟踪。
threadcreate:查看创建新操作系统线程的堆栈跟踪。

使用方法

那么接下来,我们通过一个简单的demo,来学习如何使用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
package main

import (
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
)

const release = false

func main() {
r := gin.Default()

if release {
gin.SetMode(gin.ReleaseMode)
} else {
pprof.Register(r)
}

r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run(":8088")
}

1、先执行编译并执行:

1
2
go build -o gin_pprof
./gin_pprof

2、假设我们需要分析CPU性能,那么需要执行:

1
2
3
[develop@localhost ~]$ go tool pprof --seconds 60 http://localhost:8088/debug/pprof/profile
Fetching profile over HTTP from http://localhost:8088/debug/pprof/profile?seconds=60
Please wait... (1m0s)

3、启动执行wrk程序,对接口进行压测:

1
2
[develop@localhost wrk-master]$ ./wrk -t2 -c4 -d30s http://127.0.0.1:8088/ping
Running 30s test @ http://127.0.0.1:8088/ping

4、等待60s秒后,pprof会自动保存结果,输入exit即可退出。

1
2
3
4
5
6
7
8
9
10
11
[develop@localhost ~]$ go tool pprof --seconds 60 http://localhost:8088/debug/pprof/profile
Fetching profile over HTTP from http://localhost:8088/debug/pprof/profile?seconds=60
Please wait... (1m0s)
Saved profile in /home/develop/pprof/pprof.gin_pprof.samples.cpu.001.pb.gz
File: gin_pprof
Type: cpu
Time: Oct 27, 2024 at 10:26pm (CST)
Duration: 60.01s, Total samples = 47.91s (79.83%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) exit
[develop@localhost ~]$

其中收集的性能数据文件会保存在Saved profile所在的行。

5、这里操作系统上,我使用是CentOS 7,在读取数据之前,需要安装graphviz包:

1
sudo yum install graphviz

6、通过pprof读取第4步保存完的文件:

1
2
3
4
5
[develop@localhost ~]$ go tool pprof -http 0.0.0.0:20000 /home/develop/pprof/pprof.gin_pprof.samples.cpu.001.pb.gz
Serving web UI on http://0.0.0.0:20000
Failed to open connection to "session" message bus: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11
Error: no DISPLAY environment variable specified

7、在浏览器中访问服务器上的20000端口,即可看到可视化数据。这里面我个人比较常看的是【View-Graph】和【View-Flame Graph(new)】。

1)View-Graph

2)View-Flame Graph(new)

到这里,如何使用pprof工具分析性能的流程就记录完成了,实际应用中真的非常有效,通过pprof分析结合实际业务流程,可以很快速的找到优化点。

参考

1、https://pkg.go.dev/net/http/pprof
2、https://github.com/gin-contrib/pprof
3、https://pkg.go.dev/net/http/pprof#hdr-Usage_examples