青训营性能调优实战篇

122 阅读5分钟

性能调优实战

  1. 简介

  2. 性能分析工具 pprof

  3. 性能调优案例

简介

性能调优原则

  • 要依靠数据而不是猜测
  • 要定位最大瓶颈
  • 不要过早、过度的优化

性能分析工具 pprof

可以知道应用在什么地方耗费了多少 CPU、Memory

pprof 是用于可视化和分析性能、分析数据的工具

  1. pprof 功能简介
  2. pprof 排查实战
  3. pprof 的采样过程和原理

功能简介

image.png

pprof 排查实战

项目成功运行后,使用浏览器查看指标页面,访问 localhost:6060/debug/pprof

image.png

对 CPU 性能进行排查

在终端输入以下命令

go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"

image.png

输入 topN 查看占用资源最多的前 N 个函数

top10

image.png

日志数据分析

flat: 当前函数本身的执行耗时

flat%: 当前函数执行耗时占 CPU 总消耗时间的比例

sum%: 上面每一行的 flat% 总和 (第二行 sum%的值表示前两名函数执行耗时占的比例)

cum: 指当前函数本身加上其调用函数的总耗时

cum%: 指当前函数本身加上其调用函数总耗时占总 CPU耗时的百分比

什么情况下, Flat == Cum?

当函数中没有调用其他函数时


什么情况下, Flat == 0 ?

函数中只有其他函数的调用

根据刚才的 pprof top 命令排查,我们知道了 Eat 函数是对程序性能影响最大的函数,我们使用 list 命令对函数进行进一步排查

list Eat

image.png

可以看出,for 循环是性能消耗最大的问题代码

注释掉问题代码后,重新执行检测,得到如下结果

image.png

image.png

还可以以可视化方式排查 CPU 性能问题

在终端输入 web 命令

web

image.png

同样可以定位到对 cpu 性能影响最大的函数

对内存问题进行排查

在终端输入以下命令

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

image.png

同时也有其他选项可以选择

image.png

  • Top

image.png

  • Graph

就是进入网页时的那张图

  • Flame Graph (火焰图)

image.png

  • Peek (可用于查找问题函数)

image.png

  • Source (可用于分析问题代码,类似 list + 函数的结果)

image.png

  • Disassemble 反汇编(略)

注释掉问题代码后,重新执行检测,得到如下结果

image.png

image.png

image.png

image.png

对其他问题进行排查

在 ui 界面的 SAMPLE 选项中,还包含了其他几个选项,可以对程序进行进一步优化

  • alloc_objects: 程序累计申请的对象数
  • alloc_sapce: 程序累计申请的内存大小 (可以优化掉一些额外分配的未使用的内存空间)
  • inuse_objects: 程序当前持有的对象数
  • inuse_space: 程序当前占用的内存大小 (上面分析就是基于这个选项)

image.png

goroutine 优化

类似于 cpu 和 memory 的分析方法,输入以下命令:

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

火焰图分析

  • 由上到下表示调用顺序
  • 每一块代表一个函数,越长代表占用 CPU 时间越长
  • 火焰图是动态的,支持点击块进行分析

image.png

找到问题所在,进入 Source 视图,搜索 wolf

image.png

将问题代码修改后,即可解决 goroutine 性能问题

mutex 问题、block 问题和其他问题的排查和解决方法,和上面流程类似,略

注意:在终端使用命令排查 block 时,由于系统存在过滤策略,一些 block 可能会被 drop,如果想要观察所有的 block 信息,可以使用可视化方式进行排查,那么之前被过滤的 block 也会显示出来(一般都是程序正常执行所需要的 block,所以系统将其过滤掉了)。

内容小结

image.png

pprof-采样过程和原理

  • 采样对象:函数调用和它们占用的时间
  • 采样率:100 次/秒,固定值
  • 采样时间:从手动启动到手动结束

image.png

采样原理

  • 操作系统:每 10ms 向进程发送一次 SIGPROF 信息
  • 进程:每次接收到 SIGPROF 会记录调用堆栈
  • 写缓冲:每 100ms 读取已经记录的调用栈并写入输出流

image.png

堆内存-Heap采样过程和原理

  • 采样程序通过内存分配器在堆上分配和释放内存,记录分配/释放的大小和数量
  • 采样率:每分配 512KB 记录一次,可在运行开头修改,1 为每次分配都记录
  • 采样时间:从程序运行开始到采样开始时
  • 采样指标:alloc_space, alloc_objects, inuse_space, inuse_objects
  • 计算方式:inuse = alloc - free

goroutine & ThreadCreate-线程创建的采样过程和原理

  • goroutine:记录所有用户发起且在运行中的 goroutine(即入口非 runtime 开头的)runtime.main 的调用栈信息

image.png

  • ThreadCreate:记录程序创建的所有系统线程的信息

image.png

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 为每次阻塞都记录下来(采样门槛)

image.png

Mutex

  • 采样争抢锁的次数和耗时

  • 采样率:只记录固定比例的锁操作,1 表示每次加锁都记录下来

image.png

pprof 小结

  • 掌握常用 pprof 工具功能
  • 灵活运用 pprof 工具分析解决性能问题
  • 了解 pprof 的采样过程和工作原理