性能调优实战
-
简介
-
性能分析工具 pprof
-
性能调优案例
简介
性能调优原则
- 要依靠数据而不是猜测
- 要定位最大瓶颈
- 不要过早、过度的优化
性能分析工具 pprof
可以知道应用在什么地方耗费了多少 CPU、Memory
pprof 是用于可视化和分析性能、分析数据的工具
- pprof 功能简介
- pprof 排查实战
- pprof 的采样过程和原理
功能简介
pprof 排查实战
-
pprof 工具的使用
项目成功运行后,使用浏览器查看指标页面,访问 localhost:6060/debug/pprof
对 CPU 性能进行排查
在终端输入以下命令
go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"
输入 topN 查看占用资源最多的前 N 个函数
top10
日志数据分析
flat: 当前函数本身的执行耗时
flat%: 当前函数执行耗时占 CPU 总消耗时间的比例
sum%: 上面每一行的 flat% 总和 (第二行 sum%的值表示前两名函数执行耗时占的比例)
cum: 指当前函数本身加上其调用函数的总耗时
cum%: 指当前函数本身加上其调用函数总耗时占总 CPU耗时的百分比
什么情况下, Flat == Cum?
当函数中没有调用其他函数时
什么情况下, Flat == 0 ?
函数中只有其他函数的调用
根据刚才的 pprof top 命令排查,我们知道了 Eat 函数是对程序性能影响最大的函数,我们使用 list 命令对函数进行进一步排查
list Eat
可以看出,for 循环是性能消耗最大的问题代码
注释掉问题代码后,重新执行检测,得到如下结果
还可以以可视化方式排查 CPU 性能问题
在终端输入 web 命令
web
同样可以定位到对 cpu 性能影响最大的函数
对内存问题进行排查
在终端输入以下命令
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
同时也有其他选项可以选择
- Top
- Graph
就是进入网页时的那张图
- Flame Graph (火焰图)
- Peek (可用于查找问题函数)
- Source (可用于分析问题代码,类似 list + 函数的结果)
- Disassemble 反汇编(略)
注释掉问题代码后,重新执行检测,得到如下结果
对其他问题进行排查
在 ui 界面的 SAMPLE 选项中,还包含了其他几个选项,可以对程序进行进一步优化
- alloc_objects: 程序累计申请的对象数
- alloc_sapce: 程序累计申请的内存大小 (可以优化掉一些额外分配的未使用的内存空间)
- inuse_objects: 程序当前持有的对象数
- inuse_space: 程序当前占用的内存大小 (上面分析就是基于这个选项)
goroutine 优化
类似于 cpu 和 memory 的分析方法,输入以下命令:
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine"
火焰图分析
- 由上到下表示调用顺序
- 每一块代表一个函数,越长代表占用 CPU 时间越长
- 火焰图是动态的,支持点击块进行分析
找到问题所在,进入 Source 视图,搜索 wolf
将问题代码修改后,即可解决 goroutine 性能问题
mutex 问题、block 问题和其他问题的排查和解决方法,和上面流程类似,略
注意:在终端使用命令排查 block 时,由于系统存在过滤策略,一些 block 可能会被 drop,如果想要观察所有的 block 信息,可以使用可视化方式进行排查,那么之前被过滤的 block 也会显示出来(一般都是程序正常执行所需要的 block,所以系统将其过滤掉了)。
内容小结
pprof-采样过程和原理
- 采样对象:函数调用和它们占用的时间
- 采样率:100 次/秒,固定值
- 采样时间:从手动启动到手动结束
采样原理
- 操作系统:每 10ms 向进程发送一次 SIGPROF 信息
- 进程:每次接收到 SIGPROF 会记录调用堆栈
- 写缓冲:每 100ms 读取已经记录的调用栈并写入输出流
堆内存-Heap采样过程和原理
- 采样程序通过内存分配器在堆上分配和释放内存,记录分配/释放的大小和数量
- 采样率:每分配 512KB 记录一次,可在运行开头修改,1 为每次分配都记录
- 采样时间:从程序运行开始到采样开始时
- 采样指标:alloc_space, alloc_objects, inuse_space, inuse_objects
- 计算方式:inuse = alloc - free
goroutine & ThreadCreate-线程创建的采样过程和原理
- goroutine:记录所有用户发起且在运行中的 goroutine(即入口非 runtime 开头的)runtime.main 的调用栈信息
- ThreadCreate:记录程序创建的所有系统线程的信息
GMP 模型中
- G:goroutine
- M:Thread
- P: Processor
在 Goroutine 的采样处理时,遍历的是 allg 切片
在 TheadCreate 的采样处理时,遍历的是 allm 切片
Stop The World:一般出现在 GC 过程,也称为 STW,这个过程触发时,所有程序挂起等待 GC 回收无用资源,golang 早期的 GC 算法(标记清除法)效率不高,后来接连引入了三色标记法、读写屏障,都是为了减少 STW 的时间,提高 GC 的效率。
Block-阻塞 & Mutex 的采样过程和原理
Block
采样参数
-
采样阻塞操作的次数和耗时
-
采样率:阻塞耗时超过阈值的才会被记录,1 为每次阻塞都记录下来(采样门槛)
Mutex
-
采样争抢锁的次数和耗时
-
采样率:只记录固定比例的锁操作,1 表示每次加锁都记录下来
pprof 小结
- 掌握常用 pprof 工具功能
- 灵活运用 pprof 工具分析解决性能问题
- 了解 pprof 的采样过程和工作原理