03Go高质量编程与性能调优 (下) | 青训营笔记

97 阅读6分钟

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

课程3 juejin.cn/course/byte…

课程4 juejin.cn/course/byte…

讲师: 张雷

blog.wolfogre.com/posts/go-pp… golang pprof 实战

2 性能调优实战

性能调优简介

原则

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

性能分析工具pprof实战

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

实战

blog.wolfogre.com/posts/go-pp… golang pprof 实战

以下都可以类似go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"

待-http=:8080 来生成可视化的网站

排查CPU占用过高

先go build, 然后运行程序
可浏览器打开http://localhost:6060/debug/pprof/    
然后另开终端, 执行
go tool pprof http://localhost:6060/debug/pprof/profile
等待一段时间

命令: top
将函数按资源消耗由大到小排列
flat 执行耗时
flat% flat占CPU总时间比例
sum% 本行及以上flat%的总和
cum 当前函数本身加上其调用函数的总耗时
cum% cum占CPU总时间比例
什么情况下flat==cum
函数中没有调用其它函数
什么情况下flat==0
函数中只有其它函数的调用

命令: list
利用top找到消耗资源的函数后, 可以 list [关键字], 来定位到代码
如案例中的, list Eat (试了试list E和list Eat效果一样, 应该是有靠谱的模糊查询算法)

 命令: web
调用关系可视化
需要Graphiviz才能用web命令
1.未安装Graphviz,官网链接Graphviz
graphviz.gitlab.io/download/
(我下7.0.6的报风险运行不了, 我下7.0.5的就好了)
2.下载完成后配置环境变量
用户变量Path添加: 安装路径\graphviz\bin
系统变量Path添加: 安装路径\graphviz\bin\dot.exe
3.检查是否安装成功,输入dot -version命令
// 图相关说明见文档↓
github.com/google/ppro…
读后总结:
cum(color):
red - large positive
green - large negative
grey - close to zero  flat(font size):
larger - larger absolute flat values
smaller - smaller absolute flat values
resources used along that path(edge weight)
thicker - more
thinner - fewer
some locations between the two connected locations were removed(dashed edges)
one location directly calls the other(solid edges)

排查内存占用过高

 go tool pprof http://localhost:6060/debug/pprof/heap
或者 (↓会在生成可交互的网站)
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"\  ⭐注意这里最后是heap了, 不是profile
之后同上(top list web等命令)
alloc_objects 程序累计申请的对象数
alloc_space 程序累计申请的内存大小
inuse_objects 程序当前持有对象数
inuse_space 程序当前占用内存大小

排查频繁垃圾回收

频繁的 GC 对 golang 程序性能的影响也是非常严重的
虽然现在这个炸弹程序内存使用量并不高
但这会不会是频繁 GC 之后的假象呢?
go tool pprof http://localhost:6060/debug/pprof/allocs

排查协程泄露

由于 golang 自带内存回收, 所以一般不会发生内存泄露
但凡事都有例外, 在 golang 中, 协程本身是可能泄露的, 或者叫协程失控, 进而导致内存泄露\

go tool pprof http://localhost:6060/debug/pprof/goroutine

排查锁的争用

go tool pprof http://localhost:6060/debug/pprof/mutex

排查阻塞操作

go tool pprof http://localhost:6060/debug/pprof/block

小结

pprof
分析-Profile
网页⭐
可视化终端
展示-View
Top⭐
调用图-Graph⭐
火焰图-FlameGraph⭐
Peek
源码-Source⭐
反汇编-Disassemble
工具-Tool
runtime/pprof
net/http/pprof
采样-sample
CPU
堆内存-Heap
协程-Goroutine
锁-Mutex
阻塞-Block
线程创建-ThreadCreate

采样过程和原理

CPU
采样对象: 函数调用和它们占用的时间
采样率: 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的调用栈信息
(STW: Stop the World, 当前运行的所有程序将被暂停)
STW -> 遍历allg切片 -> 输出创建g的堆栈 -> Start The World
ThreadCreate
记录程序创建的所有系统线程信息
STW -> 遍历allm链表 -> 输出创建m的堆栈 -> Start The World

Block-阻塞和Mutex-锁
阻塞操作
采样阻塞操作的次数和耗时
采样率: 阻塞耗时超过阈值的才会被记录
1为每次阻塞均记录
锁竞争
采样争抢锁的次数和耗时
采样率: 只记录固定比例的锁操作, 1为每次加锁均记录

小结

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

性能调优案例

业务服务优化
基础库优化
Go语言优化

业务服务优化

相关基本概念⭐
服务: 能单独部署, 承载一定功能的程序
依赖: Service A的功能实现依赖Service B的响应结果, 称为Service A依赖Service B
调用链路: 能支持一个接口请求的相关服务集合及其之间的依赖关系
基础库: 公共的工具包, 中间件
流程
建立服务性能评估手段
分析性能数据, 定位性能瓶颈
重点优化项改造
优化效果验证
建立服务性能评估手段
服务性能评估方式
    单独benchmark无法满足复杂逻辑分析
    不同负载情况下性能表现差异
请求流量构造
    不同请求参数覆盖逻辑不同
    线上真实流量情况
压测范围
    单机器压测
    集群压测
性能数据采集
    单机性能数据
    集群性能数据
分析性能数据, 定位性能瓶颈
如
使用库不规范
高并发场景优化不足
重点优化项改造
正确性是基础
响应数据diff
    线上请求数据录制回放
    新旧逻辑接口数据diff
优化效果验证
重复压测验证
上线评估优化效果
    关注服务监控
    逐步放量
    收集性能数据
进一步优化, 服务整体链路分析
规范上游服务调用接口, 明确场景需求
分析链路, 通过业务流程优化提升服务性能

基础库优化

AB实验SDK的优化 (AB实验就是对照实验)
分析基础库核心逻辑和性能瓶颈
    设计完善改造方案
    数据按需获取
    数据序列化协议优化
内部压测验证
推广业务服务落地验证

Go 语言优化

编译器&运行时优化
    优化内存分配策略
    优化代码编译流程, 生成更高效的程序
    内部压测验证
    推广业务服务落地验证
优点
    接入简单, 只需要调正编译配置
    通用性强

总结

性能调优原则
	要依靠数据不是猜测
性能分析工具pprof
    熟练使用pprof工具排查性能问题并了解基本原理
性能调优
    保证正确性
    定位主要瓶颈