使用 pprof 对 Go 程序进行分析优化

前言

在生产环境中,偶尔会发生 Go 程序 CPU 暴增的现象,排除某时段并发大的场景外,通过监控面板看不到程序是因为什么原因导致的,Go 语言原生就提供了工具 pprof,Google 对于 pprof 的解释就是一个用于可视化和分析数据的工具。 通过使用 Go pprof 可以对程序的 CPU性能、内存占用、Goroutine wait share resource、mutex lock 做剖面分析,我们可以使用该工具收集运行时的程序性能指标,从而分析出程序中是否由于代码编写不合理导致存在不合理的资源占用情况,从而对程序进行优化用来提升其性能。

功能

Go pprof 提供了以下五种不同维度观测其程序的功能:

  • CPU Profiling:CPU 性能分析,按照指定时间采集监听其 Go 程序 CPU 的使用情况,可以确定 Go 程序在哪个程序段中占用 CPU 耗时长;
  • Memory Profiling:内存性能分析,用来分析程序的内存堆栈区使用情况,用来检测是否存在内存泄漏;
  • Block Profiling:Goroutine 等待共享资源阻塞分析;
  • Mutex Profiling:互斥锁分析,用来报告共享资源使用互斥锁的竞争的情况;
  • Goroutine Profiling:协程性能分析,用来报告对当前运行时的 Goroutine 操作及数量。

使用

Go pprof 工具的使用也是比较简单快捷的,可以使用runtime/pprof包生成一个 profile 文件,网上也有很多的教程,这里不再过多描述了,详细可以看下包提供的函数,上面介绍了使用方法。

目前我们主要使用的是net/http/pprof包,启动一个独立端口号 http 程序单独用来 Go 程序的分析,搭配着 graphviz 组件来可视化程序来分析数据,使用起来也是比较方便的:

第一步,将net/http/pprof包引用到程序中,建议直接放在程序入口处 main.go 文件

go 复制代码
import (
    _ "net/http/pprof"
)

第二步,若本身是一个 http 的程序,不需要此步骤,若不是 http web 程序或者不想将对应信息暴露在外网,可以单开一个 http web 程序用来专门监听服务:

go 复制代码
func main() {
    // 程序逻辑代码
    
    go func() {
        _ = http.ListenAndServe(":8848", nil)
    }()
}

第三步,运行主程序,访问 pprof 界面:

sybase 复制代码
http://127.0.0.1:8848/debug/pprof/  # 主界面

http://127.0.0.1:8848/debug/pprof/allocs     # 所有过去内存分配的采样
http://127.0.0.1:8848/debug/pprof/block      # 导致同步阻塞的堆栈跟踪 
http://127.0.0.1:8848/debug/pprof/cmdline    # 当前程序的命令行的完整调用路径
http://127.0.0.1:8848/debug/pprof/goroutine  # 所有当前 Goroutine 的堆栈跟踪
http://127.0.0.1:8848/debug/pprof/heap       # 活动对象的内存分配的采样
http://127.0.0.1:8848/debug/pprof/mutex      # 争用互斥锁持有者的堆栈跟踪
http://127.0.0.1:8848/debug/pprof/profile    # CPU 配置文件
http://127.0.0.1:8848/debug/pprof/threadcreate # 创建新 OS 线程的堆栈跟踪
http://127.0.0.1:8848/debug/pprof/trace      # 当前程序执行的跟踪

后缀加上 ?debug=1 可以可视化查看对应描述,不加就可以下载成 profile 文件,使用 pprof 命令可视化查看对应数据。

第四步,使用 go tool pprof -http=:6001 profile 命令查看分析程序。

分析

上图是针对 CPU 使用做的采集可视化,箭头越粗、方块越大就代表着对应的操作消耗 CPU 大,可以看到占用 CPU 最多的操作就是 json 的序列化和反序列化操作。

同理对应的内存性能、Goroutine 阻塞的分析都可以看出对应的操作。

总结

使用 go pprof 工具可以分析解剖程序运行性能问题,可以快速定位生产环境中遇到的问题,并作出优化或者 fix bug,最后祝大家不会写出 bug code,程序稳定、头发永在。

本文首发于:blog.debuginn.com 公众号:Debug客栈

推荐阅读:

相关推荐
唐青枫1 小时前
别把泛型写复杂了:Go generic 从类型参数到实战封装
go
GetcharZp14 小时前
告别OOM!用Go+libvips实现30000×50000超大图片的流式瓦片服务
后端·go
妙码生花4 天前
从 PHP 到 AI + Golang,程序员自救转型手记(八):设计管理员模型、热重载配置
前端·后端·go
tyung5 天前
Go 手写 Wait-Free MPSC 无界队列:SwapPointer 实现多生产者无锁入队
后端·go
陈明勇5 天前
Go 1.26 新特性回顾:语言增强、工具升级与 Green Tea GC 默认启用
后端·go
妙码生花6 天前
从 PHP 到 AI + Golang,程序员自救转型手记(二):目录结构、初始化 GIT、设计并开发配置系统
前端·后端·go
leeyi6 天前
Deer-Go:字节 Deer-Flow 的 Go 移植,深度研究 Agent 全拆解
go·aigc·agent
Bolt7 天前
TypeScript 7.0 来了:当 tsc 用 Go 重写之后
javascript·typescript·go
Go_error7 天前
Datatypes:Go 轻松支持数据库JSON类型
后端·go
任沫8 天前
Agent之Function Call
javascript·人工智能·go