golang
中,pprof
是一款可视化和分析剖析数据的工具(pprof is a tool for visualization and analysis of profiling data.)
介绍
- 常用来分享 go 程序如:CPU 分析、内存分析、阻塞分析、互斥锁分析、查看 gorouting 等
- 相关的源码:
pprof
以 profile.proto 读取分析样本,提供可视化的分析报告- pprof 的使用模式Usage modes
Report generation
:生成指定格式的报告并退出,格式可以是文本或图形pprof <format> [options] source
Interactive terminal use
:交互式终端使用,pprof
将启动一个交互式 shell
,用户可以在其中输入 help
命令获取在线帮助Web interface
:Web 界面,pprof
将开始在指定端口上服务 HTTP 请求,在浏览器中访问与端口相对应的 HTTP 网址(通常为 http://<host>:<port>/
),查看界面pprof -http=[host]:[port] [options] source
net/http/pprof
package main
import (
"log"
"net/http"
_ "net/http/pprof"
)
func main() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}
go run main.go
指标说明
- 使用浏览器访问 http://localhost:6060/debug/pprof/ 既可以打开 pprof 的页面,指标说明
allocs
:过去所有内存分配的抽样block
:导致同步原语阻塞的堆栈跟踪cmdline
:当前程序的命令行调用goroutine
:当前所有 goroutine 的堆栈跟踪,可以指定 ?second=30
/debug/pprof/goroutine
- 使用
debug=2
作为查询参数,以与未恢复的 panic 相同的格式导出
heap(堆)
:实时对象的内存分配采样。可以指定 gc GET 参数,以便在采集堆样本前运行 GCmutex
:有争议的互斥项持有者的堆栈轨迹profile
:CPU 指标分析。可以在秒 GET 参数中指定持续时间,默认获取 30-second CPU profile,可以指定 ?second=30
/debug/pprof/profile
- 获取配置文件后,使用
go tool pprof xxx
命令研究配置文件
threadcreate
:导致创建新操作系统线程的堆栈跟踪/debug/pprof/threadcreate
trace(跟踪)
:当前程序的执行跟踪。可以在秒 GET 参数中指定持续时间/debug/pprof/trace
- 获取跟踪文件后,使用
go tool trace xxx
命令调查跟踪
- 参数可通过 GET 查询参数传递:
debug=N
(所有配置文件):响应格式gc=N
(堆配置文件):N>0
:剖析前运行垃圾回收周期seconds=N
(allocs、block、goroutine、heap、mutex、threadcreate 配置文件):返回 delta 配置文件seconds=N
(cpu (profile), trace profiles):在给定的持续时间内进行剖析
go tool pprof
如果没有安装 Graphviz,会报错:failed to execute dot. Is Graphviz installed?
,安装命令
# macos
brew install graphviz
# ubuntu
apt-get install graphviz
# centos
yum install graphviz
go tool pprof
中支持的指令help
帮助web
使用浏览器打开top
、top10
查看耗能 top10
- Interactive terminal use
$ go tool pprof http://localhost:6060/debug/pprof/goroutine
Fetching profile over HTTP from http://localhost:6060/debug/pprof/goroutine
Saved profile in /Users/xiexianbin/pprof/pprof.goroutine.002.pb.gz
Type: goroutine
Time: Nov 26, 2023 at 1:48pm (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 5, 100% of 5 total
Showing top 10 nodes out of 38
flat flat% sum% cum cum%
4 80.00% 80.00% 4 80.00% runtime.gopark
1 20.00% 100% 1 20.00% runtime.goroutineProfileWithLabels
0 0% 100% 1 20.00% bufio.(*Reader).Peek
0 0% 100% 1 20.00% bufio.(*Reader).ReadLine
0 0% 100% 1 20.00% bufio.(*Reader).ReadSlice
0 0% 100% 2 40.00% bufio.(*Reader).fill
0 0% 100% 1 20.00% internal/poll.(*FD).Accept
0 0% 100% 3 60.00% internal/poll.(*FD).Read
0 0% 100% 4 80.00% internal/poll.(*pollDesc).wait
0 0% 100% 4 80.00% internal/poll.(*pollDesc).waitRead (inline)
(pprof) web # 使用浏览器打开等
$ go tool pprof http://localhost:6060/debug/pprof/heap
Fetching profile over HTTP from http://localhost:6060/debug/pprof/heap
Saved profile in /Users/xiexianbin/pprof/pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
Type: inuse_space
Time: Nov 26, 2023 at 2:31pm (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 512.56kB, 100% of 512.56kB total
flat flat% sum% cum cum%
512.56kB 100% 100% 512.56kB 100% runtime.allocm
0 0% 100% 512.56kB 100% runtime.forEachP
...
参数说明:
flat
: the value of the location itself.flat%
:给定含函数的 CPU 运行耗时总比例sum%
:给定函数累积使用 CPU 总比例cum
: the value of the location plus all its descendants.cum%
:当前函数加上它之上的调用 CPU 运行耗时总比例
- Web interface,支持查看
- Top
- Graph
- Flame Graph(火焰图)
- Flame Graph (new)
- Peek
- Source 等
wget -O profile.out http://localhost:6060/debug/pprof/profile?seconds=60
go tool pprof -http=":8081" profile.out
示例
# 安装 hey,用来给服务器打流量
go install github.com/rakyll/hey@latest
# 使用 hey 打流量
hey -z 3m http://localhost:6060
# 获取 profile 并分析
wget -O profile.out http://localhost:6060/debug/pprof/profile?seconds=30
# 进入 Interactive terminal use
go tool pprof profile.out
# 打开 Web interface
go tool pprof -http=":8081" profile.out
# 同时获取 trace 并分析,将打开 web 浏览器
wget -O trace.out http://localhost:6060/debug/pprof/trace
go tool trace trace.out
# 同时获取 goroutine 并分析
go tool pprof --seconds 20 http://localhost:6060/debug/pprof/goroutine
go tool pprof http://localhost:6060/debug/pprof/goroutine?second=20
程序指定路径集成
package pprof
import (
"net/http"
"net/http/pprof"
"os"
log "github.com/sirupsen/logrus"
)
func Init() {
// https://mmcloughlin.com/posts/your-pprof-is-showing
http.DefaultServeMux = http.NewServeMux()
if os.Getenv("ARGO_PPROF") == "true" {
log.Info("enabling pprof debug endpoints - do not do this in production")
http.HandleFunc("/debug/pprof/", pprof.Index)
http.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
http.HandleFunc("/debug/pprof/profile", pprof.Profile)
http.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
http.HandleFunc("/debug/pprof/trace", pprof.Trace)
} else {
log.Info("not enabling pprof debug endpoints")
}
}
go test 生成性能分析数据
# cpu 分析
$ go test -bench=. -cpuprofile=cpu.prof
$ go tool pprof -http=:8080 cpu.prof
$ go tool pprof cpu.prof
(pprof) web
# 分析内存
$ go test -bench=. -memprofile=heap.prof
二进制程序
gin 框架
gin 框架可以直接使用 gin 官方提供的中间件 gin-contrib/pprof,示例如下:
package main
import (
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
pprof.Register(router)
router.Run(":8080")
}
- 使用 pprof 工具查看堆heap profile
go tool pprof http://localhost:8080/debug/pprof/heap
go tool pprof http://localhost:8080/debug/pprof/profile
- 在程序中调用 runtime.SetBlockProfileRate 后,查看 goroutine 的阻塞 blocking profile
go tool pprof http://localhost:8080/debug/pprof/block
wget http://localhost:8080/debug/pprof/trace?seconds=5
# 使用 go tool trace 分析