golang性能优化之pprof及其火焰图

1 pprof简介

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

  • runtime/pprof
    pprof的具体实现,所有类型的代码都可以使用。如果不是Web应用程序,建议使用该包。
  • net/http/pprof
    runtime/pprof包进行简单封装,并在http端口上暴露出来。适合Web应用程序使用。

2 pprof监控内容

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

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

3 使用pprof进行监控

一下两种使用pprof进行性能监控的方式只能生成监控信息文件,具体的分析需要使用go tool pprof [binary] file进行查看和分析。

3.1 非Web应用程序

非Web应用程序使用包runtime/pprof,生成监控文件。
下面示例进行CPU监控,并将监控数据存放在当前项目的pprof/profile_file/profile_file文件中。

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应用程序

Web应用程序使用包net/http/pprof,可以搭建Web服务器查看监控信息。通过http://locahost:6060/debug/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监控信息使用

golang原生自带pprof工具的go tool pprof [binary] file命令进入交互式终端来排查应用程序的性能问题。其中,

  • binary
    正在执行的二进制可执行程序,可选。
  • file
    pprof监控生成的文件。可以是具体的文件如profile.pprof,也可以是web站点的地址,如http://localhost:6060/debug/pprof/profile
    进入终端之后,排查性能问题的三个命令为:
  • top
    查看资源较高的调用。
  • list
    list 代码片段查看问题代码具体位置。
  • web
    在Web Browser上图形化显示当前的资源监控内容。需要事先安装graphviz
    web命令的实际行为是产生一个 .svg文件,并调用系统里设置的默认打开 .svg 的程序打开它。如果系统里打开 .svg 的默认程序并不是浏览器(比如代码编辑器),需要设置一下默认使用浏览器打开 .svg 文件。然后浏览器自动打开,可以看到:
    示例 block的监控信息

如果需要其他命令,可以在pprof交互式终端里输入help查看其他命令的使用方法。例如,

  • svg
    生成svg图。
  • pdf
    生成pdf文件,显示svg图。
  • png
    生成png图片,显示svg图。
  • ...
    当然还有很多其他的命令和选项,请自行学习验证。

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。

  1. 首先进行docker安装(ubuntu)。其他操作系统的安装参考codker安装
  2. 运行go-rorch镜像 uber/go-torch
    如果不知道相关命令,可以执行$ sudo docker run uber/go-torch -h查看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] http://localhost:8080
--suffix= pprof profile文件URL路径 /debug/pprof/profile
-t, --seconds= 执行profile的时间长度,单位是秒 30
-f, --file= 输出文件的名称 torch.svg 文件扩展名必须是 .svg
-p, --print 将生成的svg文件打印到标准输出,而不是写入文件

所有参数都是可选参数。如果没有任何参数,默认情况下,会尝试从http://localhost:8080/debug/pprof/profile 获取监控数据。
例如,从服务器http://10.0.2.15:6060/debug/pprof/block获取阻塞信息,并将生成的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生成火焰图示例

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

注:当然了,可以将go-torchFlameGraph工具分别安装,然后执行go-torch命令。具体参数和go-torch镜像执行-h显示的参数相同。此处不再赘述。

5.2 使用golang的pprof查看火焰图

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

$ 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即可显示火焰图。

pprof启动的性能分析图形化默认Web页面

pprof启动的性能分析图形化火焰图

参考

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容