使用 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客栈

推荐阅读:

相关推荐
梦想很大很大17 小时前
使用 Go + Gin + Fx 构建工程化后端服务模板(gin-app 实践)
前端·后端·go
lekami_兰1 天前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
却尘1 天前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤1 天前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
mtngt112 天前
AI DDD重构实践
go
Grassto3 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto5 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室6 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题6 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo
啊汉8 天前
古文观芷App搜索方案深度解析:打造极致性能的古文搜索引擎
go·软件随想