前言
想要进行性能优化,首先瞩目在 Go 自身提供的工具链来作为分析依据:
- net/http/pprof:采集 HTTP Server 的运行时数据进行分析
pprof开启后,每隔一段时间(10ms)就会收集下当前的堆栈信息,获取格格函数占用的CPU以及内存资源;最后通过对这些采样数据进行分析,形成一个性能分析报告。
操作
- 导入pprof包 首先,我们需要在代码中导入pprof包。在需要进行性能分析的地方,我们可以插入pprof的代码,用来记录相关的性能数据。
- 启动pprof服务 在代码中添加启动pprof服务的代码,这样我们就可以通过浏览器访问pprof的可视化界面,查看性能数据。例如,我们可以使用以下代码来启动pprof服务:
import (
_ "net/http/pprof"
)
func main() {
go func() {
if err := http.ListenAndServe(":6060", nil); err != nil {
log.Fatal(err)
}
//...
}
运行后,即可进行性能数据查看
浏览器输入localhost:端口+/debug/pprof/,该界面可以看到内存、block、协程、堆等分配的情况以及锁的操作等。
打开命令行,输入 go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"即可进入pprof工具
-
收集性能数据 在应用程序运行时,我们可以使用命令行工具或浏览器访问pprof服务来收集性能数据。以下是一些常用的命令行工具:
-
go tool pprof:用于分析CPU和内存数据。
-
go-torch:用于生成火焰图,帮助我们可视化代码的热点。
-
go tool trace:用于分析代码的执行过程。
-
分析性能数据 一旦我们收集到性能数据,就可以使用pprof工具来进行分析。pprof提供了丰富的命令和选项,可以帮助我们深入理解应用程序的性能问题。一些常用的pprof命令如下:
-
top:显示耗时最高的函数列表,例如:
以上内容分析:
`flat`: 当前函数本身的执行耗时
`flat%`:`flat`占`CPU`总时间的比例
`sum%`: 上面每一行的`flat%`总和
`cum`: 当前函数本身加上其周期函数的总耗时
`cum%`: `cum`占`CPU`总时间的比例
- 或者通过web进行访问:输入命令web,可以看到可视化的性能分析
pprof的采样过程和原理
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的调用栈信息
ThreadCreate:记录程序创建的所有系统线程的信息
Block-阻塞&Mutex-锁
阻塞操作——采样阻塞操作的次数和耗时
采样率:阻塞耗时超过阈值的才会被记录,1为每次阻塞均记录
锁竞争——采样争抢锁的次数和耗时
采样率:只记录固定比例的锁操作,1为每次加锁均记录
常见的优化技巧
除了使用pprof工具进行性能分析外,还可以采取一些常见的优化技巧来提升Go应用程序的性能。还有一些常见的优化技巧:
- 减少内存分配:尽量避免频繁的内存分配和垃圾回收操作。
- 使用并发编程:利用Go语言的并发特性来提高程序的并行性和吞吐量。
- 减少系统调用:避免不必要的系统调用,尽量使用内存缓存和异步IO等技术减少IO操作。
- 优化算法和数据结构:选择高效的算法和数据结构,能够显著提升程序的性能。