Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go 程序性能分析过程 #51

Open
jinhailang opened this issue Jun 20, 2019 · 1 comment
Open

Go 程序性能分析过程 #51

jinhailang opened this issue Jun 20, 2019 · 1 comment

Comments

@jinhailang
Copy link
Owner

jinhailang commented Jun 20, 2019

Go 程序性能分析

性能分析的目的是发现程序瓶颈,为代码优化提供指导,以及对优化结果进行量化验证。主要从内存和 CPU 使用两个维度进行分析。
Go 官方提供了功能强大的包和工具 pprof。使用过程大致分成两步:

  1. 收集运行指标数据,生成 pprof 文件;
  2. 使用命令工具 go tool pprof 解析 pprof 文件,进行分析;

下面将详细阐述。

指标收集

有三种实践方式,前两种是在程序内(一般是 main 函数内)导入包 net/http/pprof,或者使用 runtime/pprof 包。
区别是前者提供 HTTP API 接口,可以直接在 Web 页面查看,而后者是在将运行数据写入到本地文件保存。一般都选择使用前者,因为使用更简单,使用 Web 交互也更方便,还可实时查看。

package main

import (
    "net/http"
    _ "net/http/pprof"
)


func main() {
		
	// some code

    http.ListenAndServe("127.0.0.1:6060", nil)
}

浏览器访问 http://127.0.0.1:6060/debug/pprof/,可以看到如下内容:

image

需要注意的是,可以指定请求参数 seconds 来收集指定时间内的数据,例如 CPU profile: go tool pprof http://127.0.0.1:6060/debug/pprof/profile?seconds=30
我们知道,这样生成的数据文件进行数据分析才更有意义,因为一般我们都是期望对程序某个运行时间段内进行分析。

还有一种方式是使用 go test 做性能测试,直接导出 pprof 文件:

go test -cpuprofile cpu.prof -memprofile mem.prof -bench .

很明显,这种方式更适合对程序某个模块(函数)做性能分析,上面两种方式用来做程序整体的性能分析。

数据分析

生成 pprof 文件后,有两种分析方式:命令交互式和 Web 图形式。两种方式都是使用命令工具 go tool pprof

  • go tool pprof ./profile 进入交互模式,可以查看 top, 生成图片(需要安装 Graphviz 支持)或生成 DOT 格式图片(需要使用 Graphviz 转换成常见图片格式)等;

image

  • pprof -http=":8081" [binary] ./profile 创建 Web 服务,可以直接在 Web 页面查看调用图,火焰图甚至源代码等,非常方便,直观;

image

结合前面“指标收集”阶段,可以使用 API 方式获取 pprof 数据,这里还可以直接使用 url 请求来分析,以分析 5 分钟内 CPU 使用情况为例:

go tool pprof -http="127.0.0.1:8081" main.go http://127.0.0.1:6060/debug/pprof/profile?seconds=300

这么做的好处是可以实时对 CPU,内存等维度进行分析,且可以任意切换维度。

火焰图

火焰图是常用的性能分析工具,非常直观。对于很多语言来说(比如 Lua)生成火焰图的过程是很繁琐的,要借助一堆工具。在 Go 1.11 之前一般也是借助开源工具 go-torch,不过 Go 1.11 对 go tool pprof 进行了功能增强,可以直接生成火焰图等图形,因此,go-torch 项目也已经废弃了。

y 轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数。
x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它占有率更高,即执行的时间长或内存大。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的。

火焰图就是看顶层的哪个函数占据的宽度最大。只要有"平顶"(plateaus),就表示该函数可能存在性能问题。

小结

前面介绍了 Go 程序性能分析的过程,需要主要的是,只有对程序进行压测(程序达到瓶颈)的情况下,进行性能分析才有意义。
下面是工作中的一次实践过程 --- 程序压测与性能分析总结报告,作为参考。

参考

附:常用命令

  • top 查看进程 CPU,内存等使用情况
  • free 查看系统内存使用情况
  • uname -a 查看系统内核信息
  • cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l CPU 个数
  • cat /proc/cpuinfo| grep "cpu cores"| uniq CPU 核数

总核数 = 物理CPU个数 X 每颗物理CPU的核数

@jinhailang
Copy link
Owner Author

jinhailang commented Jun 20, 2019

Rule engine 程序压测报告

通过 kafka 消息对规则引擎(as-rule-engine)处理流程进行压测,计算最大 QPS,查找程序瓶颈,以及可优化的点。

核心处理流程图:

核心流程

压测的重点是上图中的 rule engine 模块,该模块是规则引擎核心模块,执行规则的匹配和结果计算。为了达到压测核心模块的目的,对入库(写 mysql)模块进行弱化,避免入库成为瓶颈。

测试环境

  • 系统:Linux test-ccd-1.hz.163.org 4.9.0-7-amd64 #1 SMP Debian 4.9.110-1 (2018-07-05) x86_64 GNU/Linux

  • CPU 核心数:2×12

  • 内存:10 G

  • Kafka

    3 台 Brokers: 10.130.49.21,10.130.49.22,10.130.49.23
    2 个 topics: anti.spider.business.uri.ip.onlinejd,anti.spider.business.ip.onlinejd

测试过程

首先,通过调节生产者生产消息速率,来间接控制规则引擎程序消息处理速率,从而到达分组压测目的。
rule engine 模块并发度可设置,通过设置不同的并发度,进行压测,压测分成四组:

测试步骤:

  1. 通过启动参数指定核心模块并发数,启动进程 as-rule-engine
  2. 设置 kafka 生产者消息写入速率阀值;
  3. 观察 kafka manger 统计页面,当 kafka topic 消息出现积压时,QPS 达到最大,停止压测;

测试结果:

序号 进程数 并发数 最大 QPS(k)
1 1 1 1.7
2 1 5 1.8
3 1 10 1.8
4 2 1 3.5

结果分析

首先,从测试结果可以发现,程序单机最大 QPS 在 1.8k 左右,而且核心模块的并发数对整个程序的性能影响很小。这就说明,程序测性能瓶颈不在核心模块,并且结合上面的流程图,可以推测,瓶颈在 kafka 消息处理(consumer) 模块。

其实,在第 4 组的测试时,在两个不同机器启动规则引擎程序,最大 QPS 结果约等于单进程时的 2 倍,就可以说明 QPS 与 消费者数量成正比。

为了进一步证明,通过 go pprof 工具获取规则引擎压测时的 CPU 火焰图。

cpu_flamegraph.zip

可以发现,在不考虑系统调用(runtime)的情况下,核心模块(Handle.func1)明显低于 consumer 模块耗费 CPU 时间。

PS: 上面的系统调用(runtime)占比也过高,应该主要是因为程序内使用了太多次锁,加解锁耗费了大量 CPU 时间。

end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant