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

91 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天

一、本节课重点内容

1. 性能调优原则

2. 性能分析工具

3. 性能调优案例

二、详细知识点介绍

1. 性能调优原则

  • 要依靠数据而不是猜测
  • 要定位最大瓶颈而不是细枝末节
  • 不要过早优化
  • 不要过度优化

2. 性能分析工具

性能调优的核心是性能瓶颈的分析,对于Go程序,最方便的是pprof工具

pprof功能说明

  • pprof是用于可视化和分析性能分析数据的工具
  • 可以知道应用在什么地方耗费了多少CPU、memory等运行指标 Snipaste_2023-01-27_12-55-05.png

pprof实践

  • 排查CPU问题

命令行分析

  • 排查堆内存问题

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

  • 排查协程问题

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

  • 排查锁问题

go tool pprof -http=:8080 “http://localhost:6060/debug/pprof/mutex”

  • 排查阻塞问题

go tool pprof -http=:8080 “http://localhost:6060/debug/pprof/block”

3. pprof的采样过程和原理

CPU采样

image.png image.png 启动采样时,进程向OS注册一个定时器,OS会每10ms向进程发送一个SIGPROF信号,进程接收到信号后就对当前调用栈进行记录。同时进程启动一个写缓冲的goroutine,它每隔100ms从进程中读取已记录的堆栈信息,并写入到输出流。当采样停止时,进程向OS取消定时器,不再接收信号,写缓冲读取不到新的堆栈时,结束输出。

堆内存采样

image.png 堆内存采样在实现上依赖内存分配器的记录,一些其他的内存分配,如栈内存、一些更底层使cgo调分配的内存,不会被采样记录,采样率是默认每分配512KB内存采样一次,采样率可以调整,设为1则每次分配都会记录。与CPU和goroutine都不同的是,内存的采样是个持续的过程,它记录从程序运行起的所有分配或释放的内存大小和对象数量,并在采样时谝历这些结果进行汇总。

协程和系统线程采样

image.png Goroutie采样会记录所有用户发起,也就是入口不是runtime开头的goroutine,以及main所在goroutine的信息和创建这些goroutine的调用栈 它们都是会在STW后,漏历所有goroutine/线程的列表〔图中的m就是GMP模型中的m,在golang中和线程对应)并输出堆栈,最后STW继续运行。该采样是立刻触发的全量记录,可以比较两个时间点的差值来得到某一时间段的指标。

阻塞操作和锁竞争采样

image.png 两指标在流程和原理上相似,不过指标的采样率含义不同:

  • 阻塞操作的采样率是个阈值,超过阈值时间的阻塞操作才会被记录,1为每次操作都会记录。炸弹程序的main里面设置rate=1
  • 锁竟争的采样率是个比例,运行时会通过随机数来记录固定比例的锁操作,1为每次操作都记录

实现也基本相同,在阻塞或锁操作发生时,会算出消耗的时间,连同调用栈一起主动上报给采样器,采样时,采样器会遍历已记录的信息,统计出具体操作次数、调用栈和总耗时。同样可以算两个时间点的差值算出短时间内的操作指标。

4. 性能调优案例

基本概念

  • 服务:能单独部署,承载一定功能的程序
  • 依赖:Service A的功能实现依赖Service B的响应结果,称为Service A依赖Service B
  • 调用链路:能支持一个接口请求的相关服务集合及其相互之间的依赖关系
  • 基础库:公共的工具包、中间件

业务优化

  • 流程
  • 建立服务性能评估手段
  • 分析性能数据,定位性能瓶颈
  • 重点优化项改造
  • 优化效果验证
  • 建立压测评估链路
  • 服务性能评估
  • 构造请求流量
  • 压测范围
  • 性能数据采集
  • 分析性能火焰图、定位性能瓶颈
  • pprof火焰图
  • 重点优化项分析
  • 规范组件库使用
  • 高并发场景优化
  • 增加代码检查规则避免增量劣化出现
  • 优化正确性验证
  • 上线验证评估
  • 逐步放量,避免出现问题
  • 进一步优化,服务整体链路分析
  • 规范上游服务调用接口,明确场景需求
  • 分析业务流程,通过业务流程优化提升服务性能

基础库优化

适应范围更广,覆盖更多服务,包括:

  • AB实验SDK的优化
  • 分析基础库核心逻辑和性能瓶颈
  • 完善改造方案,按需获取,序列化协议优化
  • 内部压测验证
  • 推广业务服务落地验证
  • Go 语言优化
  • 适应范围广通用性强,接入简单只需调整编译配置
  • 优化方式
  • 优化内存分配策略
  • 优化代码编译流程,生成更高效的程序
  • 内部压测验证
  • 推广业务服务落地验证

三、课后个人总结

在课后需要了解一下其他语言的编码规范,看是否和 Go 语言编码规范有相通之处。编码规范或者性能优化建议大部分是通用的。从链接中选择感兴趣的包,阅读官方代码。在使用Go进行并发编程时一定要规范编码,避免引发性能陷阱。