pprof性能调优实战|青训营笔记

简介: 本次课程讲解大体分为两个部分:讲述高质量编码的规范和性能调优实战,这篇文章侧重于复现使用pprof工具性能调优的实践过程,而第一部分则希望大家各自归纳总结。

这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记

前言

本次课程讲解大体分为两个部分:讲述高质量编码的规范和性能调优实战,这篇文章侧重于复现使用pprof工具性能调优的实践过程,而第一部分则希望大家各自总结归纳。

pprof性能调优实战

项目地址:https://github.com/wolfogre/go-pprof-practice

这个项目中作者埋藏了很多5个性能炸弹,故意降低了项目的性能,提高资源占用量,我们将使用pprof工具定位这些问题,并完成性能调优。

克隆项目之后,使用:go mod init go mod init github.com/wolfogre/go-pprof-practice,初始化go mod,之后就可以运行程序。

pprof预览

程序运行之后,浏览器输入http://localhost:6060/debug/pprof/,可以查看pprof监控页面。

image-20220511175314706

allocs表示分配了19次内存,block表示有3次阻塞,goroutine表示有55个协程正在运行,heap为堆上内存使用,mutex表示有1个锁竞争,threadcreate表示有7个线程创建。

通过这个面板可以先大致了解程序运行情况,并定位可能出现性能问题的位置,下面将具体排查各个问题。

优化CPU占用

我们先来看一下在活动监视器中该程序CPU占用情况:45.3%恐怖!

image-20220511180228867

在Terminal窗口输入:go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10",先pprof工具先采集10秒的数据到文件中,然后再开始接受命令去展示性能分析的结果。

image-20220511131445474

输入top命令,查看占用CPU资源较多的调用。

image-20220511131727662

  • flat:当前函数本身的执行耗时(flat == 0 则函数中只有其他函数的调用)
  • flat%:flat占CPU总时间的比例
  • sum%:上面每一行的flat%的总和
  • cum:指当前函数本身加上其调用函数的总耗时(flat == cum 则函数中没有调用其他函数)
  • cum%:cum占CPU总时间的比例

很明显github.com/wolfogre/go-pprof-practice/animal/felidae/tiger.(*Tiger).Eat的调用占用了绝大部分CPU。

定位到Eat方法占用资源最多之后,使用list Eat命令排查看出问题的代码具体是什么内容:

这里看到for循环执行了3.8s的时间,是问题所在。

image-20220511181114147

接着输入web命令,可以实现调用关系可视化,这个命令前提是需要下载graphviz,一个图形化显示调用链的工具(在后续的性能调优过程中graphviz被多次使用,这里建议先完成安装~)。

image-20220511162732237

image-20220511181314573

定位到问题之后,注释掉Tiger的Eat方法的耗时操作。

image-20220511133531958

然后查看mac活动监视器,发现CPU的占用明显降低了到了0.2%。

image-20220511181651918

在终端输入exit退出pprof的工作模式。

优化内存占用

CPU占用问题解决了,但是程序内存占用依旧过高。

image-20220511181755800

再次在终端输入go tool pprof http://localhost:6060/debug/pprof/heap命令,这次结尾是heap,表示查看堆内存的占用情况,然后依旧配合输入toplist

image-20220511182459963

可以看到,这个for循环不断给m.buffer追加1MB的内容,并设定上限1GB,暂未看到内存的释放,所以推测这就是程序占用高内存的原因。

image-20220511182531692

接着输入web,依旧会弹出一个可视化页面展示内存占用情况。

image-20220511182905185

和上面解决CPU占用问题一样,这里注释掉无效分配内存的代码。

image-20220511183302163

重启项目再看一下活动监视器,看到内存占用过大的问题也解决了。

image-20220511183406034

排查协程问题

在最上面那张pprof状态监听图上,你可能还记得协程数量有55,而此刻再刷新一下,竟然有105,所以怀疑出现了问题,下面排查一下。

image-20220511184207065

终端输入exit退出内存的监测,重新输入go tool pprof http://localhost:6060/debug/pprof/goroutine,开始监测协程的分配情况,输入top、找到占用最高的方法调用github.com/wolfogre/go-pprof-practice/animal/canidae/wolf.(*Wolf).Drink.func1

image-20220511184646802

执行list Drink,定位到了Drink方法中每调用一次Drink()都会创建10个协程,然后睡眠30秒结束。

image-20220511184736309

再照常使用一下web命令,可以看到可视化的协程的创建情况。

image-20220511185309333

依旧是将这部分循环创建协程的无意义代码注释掉,重启程序,再次查看pprof监测面板,协程的数量降低到了6,优化完成。

image-20220511190112763

排查锁争用

这是排查的第四个性能炸弹,终端输入go tool pprof http://localhost:6060/debug/pprof/mutex,接着输入top、list XXX、web定位到出现锁争用的代码,web图我就不放了。

image-20220511191012488

这里主协程调用了Lock获得锁,然后开启子协程在一秒后释放锁,主协程第二次调用Lock方法的功能是如果子协程没有调用unLock方法,则主协程依旧会阻塞在这里,等待m锁的释放,贴一段Lock方法的源码,这里注释给出了详细解释。

image-20220511191806185

关于互斥锁其实很常用,之前写作业一二都用到了,我们无法完全断定用到了锁就会被捕获为锁竞争情况,需要额外分析,这里就当作是确实发生了锁竞争,注释掉这段代码,重启项目,然后查看pprof监测面板。

image-20220511193701227

排查阻塞问题

第五个性能优化的点,因为上图中block的数量是2,表示存在阻塞,那么让我们来排查一下,在终端输入命令go tool pprof http://localhost:6060/debug/pprof/block,然后输入top、list Pee、web命令,这里web的监测图依旧没有给出。

image-20220511192726943

这里阻塞的原因是第39行代码,<-time.After实现了延时一秒的功能,那么就会因为这个人为的设定,每次多阻塞一秒,这里注释掉这部分代码,重启项目,观察pprof监测面板。

image-20220511193812023

这里看到block还有1,而且刚才toplist也只是定位到了一个block,那这个1是阻塞在哪里了?我们直接在pprof面板上点击block,可以看到这部分block是被隐藏起来的,通过观察发现是和http/server相关,推测是程序正常工作需要的阻塞。

image-20220511194229117

火焰图展示

此刻这个项目的5个性能炸弹都被我们修复了,但是课程中提到的Flame-Graph让人十分好奇,这里体验一下。依旧是在终端输入go tool pprof http://localhost:6060/debug/pprof/profile命令。

image-20220511200319042

前面说了,pprof监测工具是将数据存入一个文件再进行性能分析,这里定位到这个文件后,exit退出终端,然后重新执行go tool pprof -http localhost:3030 /Users/yucong/pprof/pprof.samples.cpu.004.pb.gz命令,这里的localhost:3030是你自己指定的网页监测工具访问端口。

然后就能访问在线的监测工具了,也可以切换各种展示方式。关于火焰图,方块的大小代表了占用 CPU 使用的长短,纵向表示调用链,颜色好像没特别的意义,只是配色很像火焰🔥。

经过测试,下面的命令可以一步直接打开在线监测平台:(将block替换成mutex、goroutine等等都可以)

`go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/block"
`

image-20220511200622003

结束语

image-20220511194514333

pprof的实战通过监测一个包含5个性能炸弹的项目,逐步修复5个性能漏洞,学习这部分的知识将为后续编写可靠的项目代码打下坚实基础~

关注微信公众号【程序员白泽】,将同步青训营期间每一课的笔记和作业。

相关文章
|
6月前
|
IDE 测试技术 Go
【字节跳动青训营】后端笔记整理-3 | Go语言工程实践之测试
用于验证已经修改或新增功能后,软件的既有功能是否受到影响。
121 2
|
存储 安全 编译器
【C++】C++入门必备知识详细讲解
【C++】C++入门必备知识详细讲解
215 0
|
6月前
|
运维 监控 Java
【深入浅出JVM原理及调优】「搭建理论知识框架」全方位带你深度剖析Java线程转储分析的开发指南
学习JVM需要一定的编程经验和计算机基础知识,适用于从事Java开发、系统架构设计、性能优化、研究学习等领域的专业人士和技术爱好者。
107 5
【深入浅出JVM原理及调优】「搭建理论知识框架」全方位带你深度剖析Java线程转储分析的开发指南
|
存储 缓存 监控
JVM关键知识点整理,从入门到提高到实践
Java 虚拟机定义了各种在程序执行期间使用的运行时数据区域。这些数据区域有一些是在Java虚拟机启动时创建的,并在Java虚拟机退出时销毁,有一些数据区域是每个线程独有的,在线程创建时创建,在线程销毁时销毁,根据《Java虚拟机规范》的规定,Java虚拟机运行时所需要管理的数据区域主要如下图所示:
345 0
JVM关键知识点整理,从入门到提高到实践
|
安全 编译器 C语言
C++入门必备知识
C++入门必备知识
58 0
|
设计模式 前端开发 JavaScript
前端Web开发学习,入门到进阶,推荐几本很不错的书籍
前端Web开发学习,入门到进阶,推荐几本很不错的书籍
162 0
|
算法 Java 程序员
阿里P8大牛精心整理JVM性能优化知识点+最新JVM面试题(附答案)
JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。它不仅是一种跨平台的软件,而且是一种新的网络计算平台。该平台包括许多相关的技术,如符合开放接口标准的各种API、优化技术等。
|
存储 缓存 前端开发
Web性能优化_知识点精讲
延迟和宽带 WebWorker 关键渲染路径 React 应用中的优化处理 利用React-Profiler提升应用性能 从 URL 输入到页面加载整过程分析 SPA 提速 SPA: SEO
164 0
Web性能优化_知识点精讲
|
编解码 运维 负载均衡
深入浅出RPC框架|青训营笔记
由于课程涉及到的RPC知识需要自己对其有较为全面的理解后才能比较好的get到课程中提及的各种框架设计的点,因此我建议阅读Kitex框架的源码,再结合课程目录去体会Kitex设计的初衷。
189 0
深入浅出RPC框架|青训营笔记
|
存储 安全 编译器
【C++入门必备知识】
库里的名称我们无法改变,那我们可以将自己定义的名称放在命名空间里,当需要时指令访问即可。 那怎么定义命名空间呢?
87 0
下一篇
无影云桌面