golang profiling

golang的火焰图,多用于跟踪程序运行的状态,CPU消耗,内存消耗等

应用(server)搜集数据

做 Profiling 第一步就是怎么获取应用程序的运行情况数据。
go 语言提供了 runtime/pprof 和 net/http/pprof 两个库

工具型应用

pprof 封装了很好的接口供我们使用,比如要想进行 CPU Profiling,可以调用 pprof.StartCPUProfile() 方法,它会对当前应用程序进行 CPU profiling,并写入到提供的参数中(w io.Writer),要停止调用 StopCPUProfile() 即可。

对于CPU:

1
2
3
4
f, err := os.Create(*cpuprofile)
...
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()

对于内存

1
2
3
f, err := os.Create(*memprofile)
pprof.WriteHeapProfile(f)
f.Close()

服务型应用

默认的net/http

如果server是默认的net/http包,那就很简答了,net/http已经集成了profiling
只需要添加一行

1
import _ "net/http/pprof"

自定义的 Mux

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

1
2
3
4
5
r.HandleFunc("/debug/pprof/", pprof.Index)
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)

beego

beego框架也是可以自定义profiling的,需要做两步

第一步,加一个controller

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
26
27
package controllers

import (
"net/http/pprof"

"github.com/astaxie/beego"
)

type ProfController struct {
beego.Controller
}

func (c *ProfController) Get() {
switch c.Ctx.Input.Param(":pp") {
default:
pprof.Index(c.Ctx.ResponseWriter, c.Ctx.Request)
case "":
pprof.Index(c.Ctx.ResponseWriter, c.Ctx.Request)
case "cmdline":
pprof.Cmdline(c.Ctx.ResponseWriter, c.Ctx.Request)
case "profile":
pprof.Profile(c.Ctx.ResponseWriter, c.Ctx.Request)
case "symbol":
pprof.Symbol(c.Ctx.ResponseWriter, c.Ctx.Request)
}
c.Ctx.ResponseWriter.WriteHeader(200)
}

第二步,注册路由

1
2
beego.Router(`/debug/pprof`, &controllers.ProfController{})
beego.Router(`/debug/pprof/:pp([\w]+)`, &controllers.ProfController{})

gin

先装一个包

1
go get github.com/DeanThompson/ginpprof

然后在使用 ginpprof.Wrapper 即可,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"github.com/gin-gonic/gin"
"github.com/DeanThompson/ginpprof"
)

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

router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})

ginpprof.Wrapper(router)
router.Run(":8080")
}

获取svg

安装依赖

在后面我们会生成调用关系图和火焰图,需要安装 graphviz 软件包
Ubuntu安装graphviz

1
$ sudo apt-get install -y graphviz

mac安装graphviz

1
brew install graphviz

当然,还需要golang的go toolgo-torch(可选)

使用go tool

1
2
3
4
go tool pprof --seconds 5 http://test-server.com/debug/pprof/profile
go tool pprof --seconds 5 http://test-server.com/game/pprof/default
go tool pprof --seconds 5 http://test-server.com/game/pprof/cmdline
go tool pprof --seconds 5 http://test-server.com/game/pprof/symbol

这种情况下获得的图是这样子的
alt text
那么问题来了,可以看个大概,但是还是不够友好,这就引出了go-torch

使用go torch

go-torch是Uber公司开源的一款针对Go语言程序的火焰图生成工具,能收集 stack traces,并把它们整理成火焰图,直观地程序给开发人员。
我们通过go-torch,可以获取到火焰图svg
获取到的svg,拖动到Chrome浏览器即可。

安装go-torch

1
go get -v github.com/uber/go-torch

使用go-torch获取svg

1
go-torch -t 30 -u http://test-server.com -f ./test1.svg

会得到如下所示的结果

1
2
3
> go-torch -t 25 -u http://test-server.com -f ./test1.svg
INFO[14:31:49] Run pprof command: go tool pprof -raw -seconds 25 http://test-server.com/debug/pprof/profile
INFO[14:32:15] Writing svg to ./test1.svg

打开svg如下图所示
alt text

这么看,是不是就可以明白了

火焰图分析

未完待续、、、