1 pprof简介

golang代码的性能监控使用pprof包来做。pprof有两个包:

runtime/pprofnet/http/pprofruntime/pprof
2 pprof监控内容

pprof监控的内容项目入下表所示。

类型 描述 备注
allocs 内存分配情况的采样信息 可以用浏览器打开,但可读性不高
blocks 阻塞操作情况的采样信息 可以用浏览器打开,但可读性不高
cmdline 显示程序启动命令及参数 可以用浏览器打开,但可读性不高
goroutine 当前所有协程的堆栈信息 可以用浏览器打开,但可读性不高
heap 堆上内存使用情况的采样信息 可以用浏览器打开,但可读性不高
mutex 锁争用情况的采样信息 可以用浏览器打开,但可读性不高
profile CPU 占用情况的采样信息 浏览器打开会下载文件
threadcreate 系统线程创建情况的采样信息 可以用浏览器打开,但可读性不高
trace 程序运行跟踪信息 浏览器打开会下载文件
3 使用pprof进行监控
go tool pprof [binary] file

3.1 非Web应用程序

runtime/pprof
import (
    "log"
    "os"
    "path/filepath"
    "runtime/pprof"
)
// 进行CPU监控
func CreateProfileFile() {
    dir, err := os.Getwd()
    if err != nil {
        log.Fatalln("get current directory failed.", err)
    }
    
    fileName := filepath.Join(dir, "pprof", "profile_file", "profile_file")
    f, _ := os.Create(fileName)
    // start to record CPU profile and write to file `f`
    _ = pprof.StartCPUProfile(f)
    // stop to record CPU profile
    defer pprof.StopCPUProfile()
    // TODO do something
}

3.2 Web应用程序

net/http/pprof
import (
    "log"
    "net/http"
    _ "net/http/pprof"
    "os"
    "runtime"
)

func main() {
    log.SetFlags(log.Lshortfile | log.LstdFlags)
    log.SetOutput(os.Stdout)

    runtime.GOMAXPROCS(1)
    runtime.SetMutexProfileFraction(1)
    runtime.SetBlockProfileRate(1)

    go func() {
        if err := http.ListenAndServe(":6060", nil); err != nil {
            log.Fatal(err)
        }
        os.Exit(0)
    }()

注意
如果你使用自定义的 Mux,则需要手动注册一些路由规则:

mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
4 pprof监控信息使用
go tool pprof [binary] file
toplistlist 代码片段webweb.svg.svg.svg.svg
help
svgpdfpng
5 pprof监控信息展示——火焰图

火焰图(Flame Graph)是 Bredan Gregg 创建的一种性能分析图表,因为它的样子近似火焰而得名。golang性能监控结果可以转换成火焰图来进行直观展示。火焰图 svg 文件可以通过浏览器打开,它展示调用图的最大优点是火焰图动态的——可以通过点击每个方块来分析它上层概况/下层详细的内容。
火焰图的调用顺序从下到上,每个方块代表一个函数,它上面一层表示这个函数会调用哪些函数,方块的大小代表了占用资源值的多少(例如,CPU使用时间的长短,内存使用的大小等)。火焰图的配色并没有特殊的意义,默认的红、黄配色是为了更像火焰而已。
生成火焰图,有两种方式:go-torch(golang version < 1.10)和golang原生的pprof(golang version < 1.10+的pprof集成了火焰图功能)。

5.1 go-torch

go-torch是uber 开源的一个工具。go-torch可以直接读取 golang 的监控数据文件,并生成一个火焰图的 svg 文件。

go-torch工具使用非常简单,最简单的是使用go-torch的docker镜像运行,无需安装go-torch。

$ sudo docker run uber/go-torch -h
Usage:
  go-torch [options] [binary] <profile source>

pprof Options:
  -u, --url=         Base URL of your Go program (default:
                     http://localhost:8080)
      --suffix=      URL path of pprof profile (default: /debug/pprof/profile)
  -b, --binaryinput= File path of previously saved binary profile. (binary
                     profile is anything accepted by
                     https://golang.org/cmd/pprof)
      --binaryname=  File path of the binary that the binaryinput is for, used
                     for pprof inputs
  -t, --seconds=     Number of seconds to profile for (default: 30)
      --pprofArgs=   Extra arguments for pprof

Output Options:
  -f, --file=        Output file name (must be .svg) (default: torch.svg)
  -p, --print        Print the generated svg to stdout instead of writing to
                     file
  -r, --raw          Print the raw call graph output to stdout instead of
                     creating a flame graph; use with Brendan Gregg's flame
                     graph perl script (see
                     https://github.com/brendangregg/FlameGraph)
      --title=       Graph title to display in the output file (default: Flame
                     Graph)
      --width=       Generated graph width (default: 1200)
      --hash         Colors are keyed by function name hash
      --colors=      set color palette. choices are: hot (default), mem, io,
                     wakeup, chain, java, js, perl, red, green, blue, aqua,
                     yellow, purple, orange
      --cp           Use consistent palette (palette.map)
      --reverse      Generate stack-reversed flame graph
      --inverted     icicle graph

Help Options:
  -h, --help         Show this help message

最重要的命令有五个:

可选参数选项 描述 默认值 备注
-u, --url= golang代码的基础URL——[scheme]://[host]:[port]
--suffix= pprof profile文件URL路径 /debug/pprof/profile
-t, --seconds= 执行profile的时间长度,单位是秒 30
-f, --file= 输出文件的名称 torch.svg 文件扩展名必须是 .svg
-p, --print 将生成的svg文件打印到标准输出,而不是写入文件

所有参数都是可选参数。如果没有任何参数,默认情况下,会尝试从 获取监控数据。
例如,从服务器获取阻塞信息,并将生成的svg文件打印到标准输出中,然后信息重定向保存到本地torch.svg文件。

$ sudo docker run uber/go-torch -u http://10.0.2.15:6060 --suffix=/debug/pprof/block -p > torch.svg
INFO[02:33:36] Run pprof command: go tool pprof -raw -seconds 30 http://10.0.2.15:6060/debug/pprof/block
INFO[02:33:36] Printing svg to stdout

第一次执行由于需要安装go-torch相关依赖和镜像,等待时间较长。
执行成功之后,本地会生成一个torch.svg文件。右键通过浏览器打开,可以看到火焰图,如下图所示:



使用go-torch的docker镜像可以在windows操作系统使用。

go-torch-h

5.2 使用golang的pprof查看火焰图

使用go tool pprof可以在Web界面上查看所有类型的资源监控图。
例如,使用pprof查看Web服务器的阻塞监控数据,并将结果展示在6061端口。通过即可查看生成的火焰图。

$ go tool pprof -http=:6061 http://localhost:6060/debug/pprof/block
Fetching profile over HTTP from http://localhost:6060/debug/pprof/block
Saved profile in /home/jerry/pprof/pprof.___go_build_main_go.contentions.delay.005.pb.gz

从执行命令的过程,可以看到pprof工具从http://localhost:6060/debug/pprof/block获取监控数据,并保存到本地:/home/jerry/pprof/pprof.___go_build_main_go.contentions.delay.005.pb.gz。然后对该文件进行分析,并启动一个Web服务器:http://localhost:6061。一般会自动弹出一个浏览器并显示结果——默认显示的是graph。但是可以从第一行的菜单中切换View,选择Flame Graph即可显示火焰图。


参考

1 golang pprof 实战
2 Go pprof和火焰图
3 使用 pprof 和火焰图调试 golang 应用
4 go pprof详细理解及使用
5 使用pprof及Go 程序的性能优化