前语
本文主要内容为Go功能调优、功能剖析东西——pprof的介绍、pprof的采样进程以及原理解析。
简介
在实践项目中,咱们都知道优化很重要,在工作中伴随着迭代的开发,代码的优化要适度进行不要过度,下面是优化的准则可供参考。
功能优化、调优准则:
- 要依托数据而不是猜想
- 要定位最大瓶颈而不是细枝末叶
- 不要过早优化
- 不要过度优化
功能剖析东西
咱们希望知道应用在什么地方耗费了多少CPU
、Memory
,有没有什么东西能够检测?
pprof
就是这样的东西,pprof
可用于可视化和剖析功能剖析数据的东西,下面将对pprof进行介绍以及简单的使用介绍。
pprof
是一个强大的功能剖析东西,能够捕捉到多维度的运转状况的数据,Go
在语言层面集成了profile
采样东西,在程序运转进程中能够获取cpu
、heap
、block
、traces
等履行信息,这些会涉及到runtime/pprof
、net/http/pprof
等包,获取profile
数据最有两种形式:web
形式与profile
文件生成形式。
pprof实战
项目建立
建立pprof
实践项目,这儿使用的是github
上一个开源项目,这个项目提前埋入了一些炸弹代码,产生可观测的功能问题,运转该项目会占用1CPU
中心和超越1GB
的内存。
开源项目地址:github.com/wolfogre/go…
将项目clone下来之后,在终端输入go run main.go
即可运转项目。
目标查看
翻开浏览器,输入地址 http://localhost:6060/debug/pprof 即可,如图。
从页面中能够查到,内存、block、协程、堆等分配的状况以及锁的操作等。
CPU
首要看一下CPU的运转状况,翻开电脑自带的活动管理器,能够看到此项目在我的电脑上占了48%
的CPU。
pprof在每运转一段时刻后,就会把运转信息输出到文件中,咱们能够经过指令来获取文件。
在终端中输入指令,获取文件:
go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"
topN
指令:top
用于查看占用资源最多的函数
参数阐明:
-
flat
: 当时函数自身的履行耗时 -
flat%
:flat
占CPU
总时刻的份额 -
sum%
: 上面每一行的flat%
总和 -
cum
: 当时函数自身加上其周期函数的总耗时 -
cum%
:cum
占CPU
总时刻的份额
从图中能够看到,Flat
列有的是0
,有的不是0
,那么Flat
在什么状况下等于Cum
?什么状况下等于0
呢?
根据上述参数阐明,能够知道:
- Flat == Cum,阐明函数中没有调用其他函数
- Flat == 0,阐明函数中只有其他函数的调用
经过top
指令,得出Eat
函数是最消耗CPU
的,下面介绍怎么定位到代码的详细行。
list
指令:list
能够根据指定的正则表达式查找代码行
输入指令list Eat
,从输出成果里能够看到对应的文件为tiger.go
,并且详细的代码行为24
行的for
循环。
web
有时候根据指令行查看成果不是很直观,pprof还供给了可视化的查看方式。
指令: web
将调用关系生成可视化文件,能够输出可视化调用量以及每个节点的资源占用数据。
找到代码进行更改,将循环次数改小一些,再次发动项目,查看资源占用状况,能够发现CPU现已没有那么高了。
Heap
经过代码的改造,能够发现CPU的问题现已处理了,可是内存使用仍是很高。
这次直接以可视化的办法查看,输入以下指令,翻开堆内存的占用状况:
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
翻开之后,会呈现一下界面:
从上图咱们一眼就能够看出,Mouse
这个目标的Steal
办法占用的内存最多。
翻开View
->Source
视图,还能够看到详细的代码文件以及对应的行数。
找到对应的代码,将代码进行注释,然后看下资源占用状况。
注释掉mouse.go
文件的第50
行。
重新运转项目,查看资源占用现已很低了。
采样阐明,SAMPLE
菜单中有几个选项,对应阐明如下:
- alloc_objects: 程序累计请求的目标数
- alloc_space: 程序累计请求的内存大小
- inuse_objects: 程序当时持有的目标数
- inuse_space: 程序当时占用的内存大小
协程
goroutine
泄露也会导致内存泄露
以可视化的办法查看,输入以下指令,翻开堆内存的占用状况:
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine"
火焰图阐明:
- 由上到下标识调用次序
- 每一块代表一个函数,越长代表占用CPU时刻更长
- 火焰图是动态的,支撑点击块进行剖析
切换到Source视图,查看代码详细位置。
能够看出wolf.go
文件里的第34
行,协程里进行了睡眠30s
,修正此处代码即可修正该问题。
mutex
经过pprof
查看锁相关问题,比方加锁时刻长等。
履行指令:
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/mutex"
输出界面如下:
切换到代码视图:
能够发现,wolf.go文件里在开释锁前,进行了睡眠操作,对此处代码进行修正即可修正问题。
block
查看代码中是否存在堵塞,履行指令:
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/block"
输出界面如下:
切换到Source
视图,能够看到cat.go
文件里存在堵塞行为:
同样的,经过top
指令也能够看到存在问题的文件。
pprof原理
下面介绍一下pprof的采样进程以及实现原理。
CPU
采样目标:函数调用和他们占用的时刻
采样率:100次/秒,固定值
采样时刻:从手动发动到手动结束
采样详细流程如下:
流程阐明:
- 操作体系:每10ms向进程发送一次
SIGPROF
信号 - 进程:每次接收到
SIGPROF
信号会记载调用仓库 - 写缓冲:每100ms读取现已记载的调用栈并写入输出流
堆内存
堆内存采样进程如下:
- 采样程序经过内存分配器在堆上分配和开释内存,记载分配/开释的大小和数量
- 采样率:每分配512KB记载一次,可在运转开头修正,1为每次分配均记载
- 采样时刻:从程序运转开端到采样时
- 采样目标:alloc_space, alloc_objects, inuse_space, inuse_objects
- 计算方式:inuse = alloc – free
协程&线程创立
协程和线程创立在实现上十分的类似,都是会在STW之后,遍历所有goroutine/所有线程的列表并输出仓库,最后Start The World持续运转。这个采样是立刻触发的全量记载,能够经过比较两个时刻点的差值来得到某一时刻段的目标。
协程(Goroutine)
记载所有用户建议且在运转中的goroutine(即进口非runtime开头的)runtime.main的调用栈信息
线程创立(ThreadCreate)
记载程序创立的所有体系线程的信息
协程和线程创立的采样流程如下:
Block&Mutex
堵塞和锁竞争这两个目标在流程和原理也十分类似,这两个采样记载的都是对应操作产生的调用栈、次数和耗时,不过这两个目标的采样率意义并不相同。
堵塞操作的采样率是一个”阈值“,消耗超越阈值时刻的堵塞操作才会被记载,1为每次操作都会记载。
锁竞争的采样率是一个”份额“,运转时会经过随机数来只记载固定份额的锁操作,1为每次操作都会记载。
堵塞操作的采样操作:
- 采样堵塞操作的次数和耗时
- 采样率:堵塞耗时超越阈值的才会被记载,1为每次堵塞均记载
锁竞争的采样操作:
- 采样争抢锁的次数和耗时
- 采样率:只记载固定份额的锁操作,1为每次加锁均记载
堵塞和锁竞争的采样流程如下:
总结
本文主要内容为Go功能调优、功能剖析东西——pprof
,pprof
供给了指令行、可视化等排查问题手段,本文经过代码实践运转排查代码中存在的功能问题,经过pprof
能够方便快捷的排查代码中呈现的CPU
、内存、仓库、协程、block
、锁等各个方面的问题。
尽管比如比较简单,可是经过这个比如能够使咱们快速上手pprof
东西的使用办法,为之后排查问题、功能优化奠定了良好的根底。
引证
功能优化剖析东西
功能调优实战事例