...menustart
...menuend
- CPU profile
- Memory Profile(Heap Profile)
- Block Profiling:报告 goroutines 不在运行状态的情况,可以用来分析和查找死锁等性能瓶颈
- Goroutine Profiling:报告 goroutines 的使用情况,有哪些 goroutine,它们的调用关系是怎样的
runtime/pprof
net/http/pprof
go test
-
如果你的应用是一次性的,运行一段时间就结束。那么最好的办法,就是在应用退出的时候把 profiling 的报告保存到文件中,进行分析。
-
对于这种情况,可以使用 runtime/pprof 库。
-
pprof 封装了很好的接口供我们使用.
-
比如要想进行 CPU Profiling,可以调用 pprof.StartCPUProfile() 方法
- 它会对当前应用程序进行 CPU profiling,并写入到提供的参数中(w io.Writer),要停止调用 StopCPUProfile() 即可.
// 一般写在写在 main.go 文件中
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal("could not create CPU profile: ", err)
}
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal("could not start CPU profile: ", err)
}
defer pprof.StopCPUProfile()
- 要获得内存的数据,直接使用 WriteHeapProfile 就行, 不用 start 和 stop 这两个步骤了:
f, err := os.Create(*memprofile)
pprof.WriteHeapProfile(f)
f.Close()
-
如果你的应用是一直运行的,比如 web 应用,那么可以使用 net/http/pprof 库, 它提供 HTTP 服务进行分析
-
- [推荐] 如果使用了默认的 http.DefaultServeMux(通常是代码直接使用
http.ListenAndServe("0.0.0.0:8000", nil)
) ,只需要添加一行:
import _ "net/http/pprof"
- [推荐] 如果使用了默认的 http.DefaultServeMux(通常是代码直接使用
-
- 如果你使用自定义的 Mux,则需要手动注册一些路由规则: 比如
- 不推荐
// r.HandleFunc("/debug/pprof/", pprof.Index) // must end with '/' // r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) // r.HandleFunc("/debug/pprof/profile", pprof.Profile) // r.HandleFunc("/debug/pprof/symbol", pprof.Symbol) // r.HandleFunc("/debug/pprof/trace", pprof.Trace)
-
即便你是 第2中情况, 你依然可以 额外启动一个 http 服务 来提供 pprof
import _ "net/http/pprof
...
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
- 不管哪种方式,你的 HTTP 服务都会多出
/debug/pprof/
endpoint,访问它会得到类似下面的内容:
/debug/pprof/
profiles:
0 block
62 goroutine
444 heap
30 threadcreate
full goroutine stack dump
- 这个路径下还有几个子页面:
- /debug/pprof/profile:访问这个链接会自动进行 CPU profiling,持续 30s,并生成一个文件供下载
- /debug/pprof/heap: Memory Profiling 的路径,访问这个链接会得到一个内存 Profiling 结果的文件
- /debug/pprof/goroutines:运行的 goroutines 列表,以及调用关系
- ...
go tool pprof
命令行工具- 如果要生成调用关系 和 火焰图, 需要安装 graphviz .
- 使用方式为
go tool pprof [binary] <source>
- binary 是 应用程序的二进制文件, 用来解析各种符号
- source 表示 profile 数据的来源, 可以是本地的文件,也可以是 http 地址, 比如
go tool pprof ./hyperkube http://172.16.3.232:10251/debug/pprof/profile
- 这个命令会进行 CPU profiling 分析,等待一段时间(默认是 30s,如果在 url 最后加上 ?seconds=60 参数可以调整采集数据的时间为 60s). 之后,我们就进入了一个交互式命令行,可以对解析的结果进行查看和导出。
- 可以通过 help 来查看支持的自命令有哪些。
- 一个有用的命令是 topN,它列出最耗时间的地方: 比如 top10
- web 命令 : 在交互模式下输入 web,就能自动生成一个 svg 文件,并跳转到浏览器打开,生成了一个函数调用图.
- 要想更细致分析,就要精确到代码级别了,看看每行代码的耗时,直接定位到出现性能问题的那行代码。
- list 命令后面跟着一个正则表达式,就能查看匹配函数的代码以及每行代码的耗时:
list yourCodeRegularExpression
weblist <regex>
打开一个页面,同时显示源码 和 汇编代码
- list 命令后面跟着一个正则表达式,就能查看匹配函数的代码以及每行代码的耗时:
- NOTE:
- 更详细的 pprof 使用方法可以参考 pprof --help 或者 pprof 文档
- tips
- 如果应用比较复杂,生成的调用图特别大,看起来很乱,有两个办法可以优化:
- 使用 web funcName 的方式,只打印和某个函数相关的内容
- 运行 go tool pprof 命令时加上
--nodefration=0.05
参数,表示如果调用的子函数使用的 CPU、memory 不超过 5%,就忽略它,不要显示在图片中
- 如果应用比较复杂,生成的调用图特别大,看起来很乱,有两个办法可以优化:
- 启动 pprof web ui:
$ go tool pprof -http=:8080 [binary] profile.out
- go test 命令有两个参数和 pprof 相关,它们分别指定生成的 CPU 和 Memory profiling 保存的文件:
- -cpuprofile:cpu profiling 数据要保存的文件地址
- -memprofile:memory profiling 数据要报文的文件地址
- 比如下面执行go test的同时,也会执行 CPU profiling,并把结果保存在 cpu.prof 文件中:
$ go test -bench . -cpuprofile=cpu.prof
- 执行结束之后,就会生成 main.test 和 cpu.prof 文件。要想使用 go tool pprof,需要指定的二进制文件就是 main.test。
- 等效于上面的CPU profile等