Go高级工程师实战营-深度Go语言大厂真实项目性能优化
一、性能优化工具-pprof
1. 简介
性能调优原则。
- 要依靠数据不是猜测。
- 要定位最大瓶颈而不是细枝末节。
- 不要过早优化。
- 不要过度优化。
2. 性能分析工具 pprof
熟练使用 pprof 工具排查性能问题并了解其基本原理。
pprof是golang的内置可视化性能分析工具,性能分析工具 pprof 是一个能够帮助用户分析并定位程序运行时性能瓶颈的工具。pprof 能够捕获和分析 CPU 、 Memory 、 Networx 和 Function 的性能信息,这些信息可以用来了解程序的运行状况并进行优化。
以下是 pprof 的详细介绍:
- 生成火焰图:pprof 可以生成 SVG 或者 PNG 格式的火焰图。火焰图是一个可视化工具,用于分析性能问题。它将性能数据可视化为水平柱状图,每一个柱子代表一个函数,宽度表示执行的时间,高度表示时间复杂度或调用次数。火焰图可以清晰地展示程序的运行情况,帮助用户快速定位性能瓶颈。
- 收集性能数据:pprof 通过向程序中添加代理来收集性能数据。这些代理会捕获程序执行时的性能数据,并将其保存在特定的文件中。然后,用户可以使用 pprof 工具分析这些文件并获得有关程序性能的信息。
- 分析数据:pprof 提供了丰富的命令行选项,可以帮助用户分析性能数据。常用的命令包括
top
、goroutine
、mutex
、heap
、callgrind
等。这些命令可以用于分析程序的 CPU 、 Memory 、 Networx 和 Function 的性能。 - 可视化界面:pprof 提供了基于 web 的可视化界面,可以帮助用户更方便地分析和展示性能数据。用户可以通过 http://localhost:6060/debug/pprof/ 访问可视化界面。
- 自定义性能分析:pprof 提供了丰富的自定义选项,可以帮助用户根据具体需求进行性能分析。例如,用户可以通过
go tool pprof
命令自定义分析程序中的某个函数,或者通过配置文件自定义分析选项。 - 社区支持:pprof 有一个活跃的社区,用户可以在社区中寻求帮助,学习新的性能分析技巧,分享自己的经验。
pprof 是当程序占用资源异常时才需要启用的工具
3.搭建pprof项目
先要下载图形化依赖安装
通过链接找适合自己操作系统的安装方法
运行该项目会占用1CPU
核心和超过1GB
的内存。
开源项目地址:github.com/wolfogre/go…
-
package main
-
-
import (
-
"log"
-
"net/http"
-
_ "net/http/pprof"// 自动注册pprof的handler到http server
-
"os"
-
"runtime"
-
"time"
-
"github.com/wolfogre/go-pprof-practice/animal"
-
)
-
-
func main() {
-
log.SetFlags(log.Lshortfile | log.LstdFlags)
-
log.SetOutput(os.Stdout)
-
-
runtime.GOMAXPROCS(1)//限制 CPU 使用数
-
runtime.SetMutexProfileFraction(1)//开启锁调用跟踪
-
runtime.SetBlockProfileRate(1)// 开启阻塞调用跟踪
-
-
go func() {
-
//启动http server
-
if err := http.ListenAndServe(":6060", nil); err != nil {
-
log.Fatal(err)
-
}
-
os.Exit(0)
-
}()
-
-
for {
-
for _, v := range animal.AllAnimals {
-
v.Live()
-
}
-
time.Sleep(time.Second)
-
}
-
}
打开浏览器,输入地址 Download | Graphviz 即可,
4.浏览器查看指标
5.cpu占用过高
打开活动监视器发现cpu占有过高,在终端输入
go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"
使用 go tool pprof
来采集 10 秒 CPU 数据排查下问题
输入
top
查看cpu占用高的原因
我们观察到Eat的方法CPU占用过高,,输入
list Eat
检查具体在代码哪个位置?
我们看到具体的代码行为24行的100亿次for循环导致的问题
在终端继续输入
web
生成一个.svg文件,系统默认打开
修改eat函数,问题旁有箭头显示
发现问题已修复
6.内存占用过高(Heap-堆内存)
我们发现内存使用还是很高
输入以下命令可以看到堆内存的占用情况:
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
7、协程(groutine)
goroutine
泄露也会导致内存泄露
我们看到debug页面协程数有106条,虽然不多,但是显然不正常
查看堆内存占用情况:
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine"
新的:
旧的:
我们在火焰图中可以看到 wolf.(*Wolf).Drink.func1
这个函数占了总 goroutine 最多
我们可以看到Drink 方法每次会起 10 个协程,每个协程会 sleep 30 秒再推出,而 Drink 函数又被反复的调用,这才导致了大量的协程泄漏。
之后就是的过程就熟悉了
7.Mutex(锁)
接着检查性能问题,首先检查不合理的锁争用问题(加锁太长等等),我们发现有一个 mutex
争用问题:
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/mutex