Go学习_30_Golang代码性能分析工具

2020-06-11 10:59:34 浏览数 (1)

Golang内置了一些性能分析工具,可以将性能分析的结果文件输出,我们可以使用图形化的工具查看分析结果,在使用这些工具之前,我们需要安装一些工具,以便于查看分析文件。

为了支持查看图形化分析结果,首先需要安装graphviz工具:

代码语言:javascript复制
brew install graphviz

为了方便调用Golang的分析工具,我们需要将$GOPATH/bin加入到$PATH中去:

  • 在Windows中通过环境变量设置
  • 在Mac下,通过vim ~/.bash_profile打开设置文件,添加配置如下:

uber提供了go-torch工具可以将分析结果文件以火焰图的方式进行展示,在go1.11之后的版本中go-torch被内置到了golang中,当然要是本地没有go-torch工具,可以通过以下步骤安装go-torch工具:

1. 安装go-torch

代码语言:javascript复制
go get github.com/uber/go-torch

2. 下载并复制flamegraph.pl(可在https://github.com/brendangregg/FlameGraph下载)文件到$GOPATH/bin路径下。

golang通过将性能测试文件输出的方式给出性能测试的结果,我们可以通过go tool查看性能分析文件。

当我们想要对特定代码片段进行性能分析的时候,可以手动调用runtime/pprof下的API进行性能分析,runtime/pprof的API文档:

代码语言:javascript复制
https://studygolang.com/pkgdoc

下面我们通过runtime.pprof对一段二维数组操作的代码片段进行性能检测:

首先是对二维数据的两个操作函数:

分别对二维数组进行随机填充,并对二维数组的每一行进行加和操作。

然后编写使用runtime.pprof对目标代码片段的测试代码:

【代码说明】

1. CPUProfile测试代码需要放在待测试代码片段的前面,调用pprof.StartCPUProfile()函数开启pprof测试,我们知道golang的函数在执行完所有的代码之后,会调用函数内部定义的defer函数,所以在此处的defer函数中调用一下pprof.StopCPUProfile()来结束本次测试;

代码语言:javascript复制
defer func() {    pprof.StopCPUProfile()}()// 也可以简写成defer pprof.StopCPUProfile()

2. 上面代码中,在待测试代码的后面有两段性能信息导出代码(堆栈信息导出、协程信息导出),这两部分的代码负责将pprof测试信息中的指标导出到profile文件中,所以要放在待测试代码片段的后面执行;

3. 上面代码中导出协程信息使用了pprof.Lookup(flagTag)函数,要是想要导出其他的性能flag信息,只需要给pprof.Lookup()函数传入不同的flag,支持的flag可以从下面的文件中查看:

代码语言:javascript复制
https://golang.org/src/runtime/pprof/pprof.go

编写好性能测试代码之后,我们就可以对待测试代码进行性能检测了,检测的步骤:

(1)build源代码文件生成可运行的二进制文件:

代码语言:javascript复制
go build main.go

可以看到生成了一个可执行的二进制文件:

(2)运行二进制文件生成性能测试文件:

可以看到输出了3个profile文件。

(3)查看profile文件,首先查看一下cpu.prof文件:

代码语言:javascript复制
// 命令:go tool pprof <二进制文件名> <要查看的profile文件>go tool pprof main cpu.prof

运行上面的命令之后,就会进入pprof的交互控制台:

使用top命令查看cpu使用情况:

上图中我们可以看到本次此时过程中各个函数执行的情况,比如main函数中的fillMatrix执行的时间占了总执行时间的97.61%,花费了2450ms。

我们还可以通过list funcName来查看指定函数具体的耗时情况:

list fillMatrix命令为我们打印出了fillMatrix函数中耗时最长的是二维数组的赋值。

同样的golang还允许我们以图形化的方式查看函数的耗时情况,使用svg命令可以将所有函数运行情况以svg格式输出:

当我们想要退出pprof工具的时候,可以使用exit命令:

我们可以将该svg图拖拽到浏览器中查看:

上图中红色矩形越大的表示CPU耗时越长,箭头表示整个程序执行的顺序关系。

下面我们使用go-torch查看一下函数执行情况的火炬图,首先使用go-torch命令生成火炬图的:

上面的命令生成了一张torch.svg的图片文件,我们将其拖拽到浏览器中进行查看:

将光标指向不同的火焰柱状图可以查看到不同函数执行是消耗的CPU时间情况。

同样的我们也可以使用命令查看mem.prof中各个函数在执行的过程中对内存的占用情况:

代码语言:javascript复制
go tool pprof main mem.prof

上图中我们可以看到二维数据占用了绝大多数的内存。

在性能测试的过程中,有时候我们需要查看一下我们的变量在系统发生GC之后,垃圾变量是否可以被成功的回收,我们可以在输出mem.prof文件内容之前,手动触发一次GC:

按照上面的命令,重新build二进制文件,并运行新的二进制文件,生成mem.prof文件,并进行查看:

我们发现在触发了GC之后,内存占用明显的降低了,从之前的1.49G降低到了1.72M,说明我们声明的变量是GC友好的,可以被系统成功的回收。

上面的测试方式适合我们在开发的过程中对代码片段进行性能检测,而对于线上运行的代码,我们不可能让线上程序一直输出测试文件,这样会影响到线上业务,不过pprof同样提供了线上代码性能测试的方法,运行我们通过http请求对线上任务进行一定时长的采样。

使用pprof对线上业务进行性能采样的步骤和要求:

  • 在应用程序中导入 "net/http/pprof"的包,并启动http server
  • 通过http://<host>:<port>/debug/pprof访问目标服务器
  • 使用下面的命令开始对线上业务进行采样
代码语言:javascript复制
// pprof进行采样// seconds参数可以指定采样时长,默认采样时间30sgo tool pprof http://<host>:<port>/debug/pprof/profile?seconds=10
// 同样可以使用go-torch进行线上采样生成火焰图go-torch -seconds 10 http://<host>:<port>/debug/pprof/profile

在gin框架中使用pprof进行性能数据采样测试

为了测试pprof和go-torch对线上代码性能的测试,下面首先使用gin框架搭建一个简单的http服务:

该Http服务提供了两个访问接口,/ 和 /fb,后者循环生成多次斐波那契数列。我们直到使用pprof对线上业务进行性能采样测试的时候,必须启动一个golang内置的http server,那么我们通过gin框架也可以满足这个条件吗?我们查看gin的Run(listenPort)源码:

从上面的gin源码可以看到gin的Run函数内部其实也是使用http包进行Http Server的启动。其实不止gin框架,我们常用的beego和iris框架,追踪源码我们会发现,它们也是通过http包启动server服务的,因此当我们使用这些框架进行http server开发,同样可以使用pprof进行线上业务的采样测试。但是在正式使用pprof对gin框架的http server进行测试之前,我们还需要安装gin对pprof的封装包:

代码语言:javascript复制
go get github.com/DeanThompson/ginpprof

并在程序中开启ginpprof服务,如上图代码中。

编写完gin的服务器之后,我们通过命令启动http服务:

在浏览器中进行访问:

服务启动成功。

请求连接就可以看到下面的测试网页:

点击就可以查看到不同的测试数据。

我们也可以通过命令行进行性能数据的采样:

上面进行了20s的性能数据采样,当采样结束之后,命令行会自动进入pprof交互模式,这时我们就可以通过命令进行文件查看了:

同样的也可以通过go-torch进行采样分析:

同样的,在指定的采样时间结束之后,go-torch就会结束采样,并将svg的文件输出到命令行文件目录下,我们可以在本地找到这个torch.svg文件,并将其拖拽到浏览器中查看:

在iris框架下使用pprof进行性能数据的采样测试

和gin框架一样,我们首先需要搭建一个iris的http服务(下面使用了v12版本的iris):

和golang内置的http server以及gin框架有所不同,iris下使用pprof工具,我们需要手动添加两个访问接口,添加完上述代码之后,运行iris服务:

代码语言:javascript复制
go run main.go

在浏览器中测试访问接口:

服务启动成功。

同样的我们可以通过url来查看pprof的性能数据:

通过命令行来查看pprof采样数据:

代码语言:javascript复制
go tool pprof http://127.0.0.1:8081/debug/pprof/heap?seconds=10

在命令行中输入上面的请求,会采样最近10s内线上服务堆栈使用的情况,在输入命令之后,会立即dump并进入到pprof的交互控制台(这和查看profile不太一样):

查看一下iris的middleware/pprof包中的New方法,从源码我们可以看到,iris内部也是使用了golang内置的net/http/pprof进行性能数据的采样,除了profile和heap,我们还可以查看的数据指标也可以从源码中看到:

同样的使用go-torch对性能数据进行采样并输出火焰图:

将火焰图拖拽到浏览器中查看:

0 人点赞