当你的Go服务上线后,你肯会遇到这些问题:
-
CPU超过90%甚至100%
-
内存突然飙升
-
某个接口偶尔变慢
-
某段代码特别耗时
pprof就是Go官方为你准备的扫描仪,用来帮你看清程序内部发生了什么。
1、pprof是什么
pprof是Go内置的性能分析工具,支持以下分析:
| 类型 | 用途 |
| CPU Profile | 查看CPU热点,找出最耗时的函数 |
| Heap Profile | 找出内存占用、内存泄漏来源 |
| Goroutine | 查看当前goroutine调度、阻塞情况 |
| Mutex | 分析锁竞争 |
| Block | 识别由于通道、锁等被阻塞的点 |
2、如何使用pprof(Web方式)
最常用:用于Web服务(Gin/标准http)
package main
import (
"log"
"net/http"
_ "net/http/pprof"
)
func main() {
//开启pprof的方式
go func() {
log.Println(http.ListenAndServe(":6060", nil))
}()
http.ListenAndServe(":8080", nil)
}
启动服务后,访问以下地址:
| 指标 | 地址 |
| CPU | http://localhost:6060/debug/pprof/profile?seconds=30 |
| 内存 | http://localhost:6060/debug/pprof/heap |
| goroutine | http://localhost:6060/debug/pprof/goroutine |
| web汇总 | http://localhost:6060/debug/pprof/ |
web汇总如图
3、单独在代码中采集 CPU Profile和内存
3.1 主要用于命令行工具
f, _ := os.Create("cpu.prof")
pprof.StartCPUProfile(f)
time.Sleep(30 * time.Second)
pprof.StopCPUProfile()
3.2 内存
f, _ := os.Create("mem.prof")
pprof.WriteHeapProfile(f)
4、如何查看pprof文件
4.1 命令行查看
go tool pprof cpu.prof
4.2 打开web页面查看
go
8081
会自动弹出web界面
5、查看火焰图
火焰图的核心规则是:越宽的块=越多的CPU时间/内存占用;越高的块=调用链更深
6、举个实例
package main
import (
"log"
"math"
"net/http"
_ "net/http/pprof"
)
// 这个函数消耗大量的CPU计算
func slow() {
for i := 0; i < 1e7; i++ {
math.Sqrt(float64(i))
}
}
func main() {
//开启pprof的方式
go func() {
log.Println(http.ListenAndServe(":6060", nil))
}()
http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
slow()
w.Write([]byte("done"))
})
http.ListenAndServe(":8080", nil)
}
启动服务,然后不断地访问测试地址,同时收集cpu的pprof信息
//收集cpu信息
curl http://localhost:6060/debug/pprof/profile?seconds=20 -o cpu.prof
//查看火焰图
go tool pprof -http=:8081 cpu.prof
启动火焰图后,我们看见确实math.Sqrt占用了大量的CPU资源。这就是你要优化的地方。
7、内存泄漏定位示例
var data [][]byte
func leak() {
b := make([]byte, 10<<20) // 10MB
data = append(data, b) // 不断增长
}
采集内存
curl
6060
20
打开火焰图
go
8082
在图上我们看见main.leak占用内存最多。
8、Go性能优化的基本思路
CPU优化方向
-
减少不必要的计算
-
热点函数重写
-
使用更高效的数据结构
-
较少锁竞争
-
避免gotoutine大量创建销毁
内存优化方向
-
减少临时对象分配,使用对象复用池 sync.Pool
-
减少逃逸到堆,减少返回指针、减少使用局部变量
-
检查是否存在内存泄漏
-
缓存热点数据
并发优化方向
-
尽量减少共享内存
-
任务拆分避免过度
-
避免无约束的goroutine,用worker pool
9、安全
生产环境不要暴露pprof,可用内网防火墙或者白名单可以访问,其他的均禁止。
10、源码地址
性能优化和人生一样,不是拼命就能更快,而是找到真正拖慢你的瓶颈,持续迭代,人生和程序都会跑的更快更稳。
如果您喜欢这篇文章,请点赞、推荐+分享给更多朋友,万分感谢!