什么是pprof?
代码上线前可以通过压测可以获知系统的性能,例如每秒能处理的请求数,平均响应时间,错误率等指标。可以对性能有初步的估计
但是压测是线下的模拟流量,线上可能会遇到高并发、大流量,不靠谱的上下游,突发的尖峰流量等等场景,这些都是不可预知的。
线上突然大量报警,接口超时,错误数增加,除了看日志、监控,就是用性能分析工具分析程序的性能,找到瓶颈。当然,一般这种情形不会让你有机会去分析,降级、限流、回滚才是首先要做的,要先止损。回归正常之后,通过线上流量回放,或者压测等手段,制造性能问题,再通过工具来分析系统的瓶颈。
一般而言,性能分析主要关注 CPU、内存、磁盘 IO、网络这些指标。
Profiling 是指在程序执行过程中,收集能够反映程序执行状态的数据。在软件工程中,性能分析(performance analysis,也称为 profiling),是以收集程序运行时信息为手段研究程序行为的分析方法,是一种动态程序分析的方法。
1. 数据采样
pprof 采样数据主要有三种获取方式:
- runtime/pprof: 采集程序(非server)的运行数据,手动调用runtime.StartCPUProfile或者runtime.StopCPUProfile等API来生成和写入采样文件,灵活性高
- net/http/pprof: 采集HTTP server的运行数据,通过 http服务获取Profile采样文件,简单易用,适用于对应用程序的整体监控。
1.1 runtime/pprof
拿 CPU profiling 举例,增加两行代码,调用 pprof.StartCPUProfile 启动 cpu profiling,调用 pprof.StopCPUProfile() 将数据刷到文件里:
import "runtime/pprof"
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func main() {
// …………
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
// …………
}
1.2 net/http/pprof
启动一个端口(和正常提供业务服务的端口不同)监听 pprof 请求:
import _ "net/http/pprof"
go func() {
log.Println(http.ListenAndServe("localhost:8080", nil))
}()
pprof 包会自动注册 handler, 处理相关的请求:
// src/net/http/pprof/pprof.go:71
func init() {
http.Handle("/debug/pprof/", http.HandlerFunc(Index))
http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
}
启动服务后,直接在浏览器访问:
http://127.0.0.1:8080/debug/pprof/
可以得到以下内容

可以直接点击上面的链接,进入子页面,查看相关的汇总信息
点击 profile 和 trace 则会在后台进行一段时间的数据采样,采样完成后,返回给浏览器一个 profile 文件,之后在本地通过 go tool pprof 工具进行分析。
当我们下载得到了 profile 文件后,执行命令:
go tool pprof ~/Downloads/profile
就可以进入命令行交互式使用模式。执行 help 可以查看帮助信息。
直接使用如下命令,则不需要通过点击浏览器上的链接就能进入命令行交互模式:
go tool pprof http://127.0.0.1:8080/debug/pprof/profile
当然也是需要先后台采集一段时间的数据,再将数据文件下载到本地,最后进行分析。上述的 Url 后面还可以带上时间参数:?seconds=60,自定义 CPU Profiling 的时长。
# 下载 cpu profile,默认从当前开始收集 30s 的 cpu 使用情况,需要等待 30s
go tool pprof http://127.0.0.1:8080/debug/pprof/profile
# wait 60s
go tool pprof http://127.0.0.1:8080/debug/pprof/profile?seconds=60
进入交互式模式之后,比较常用的有 top、 list、 web 等命令。
除了 cpu 使用情况外,线上问题排查还需要关注内存使用问题:
# 下载内存使用svg图到本地
go tool pprof -inuse_space -cum -svg http://ip:port/debug/pprof/heap > heap_inuse.svg
2. 可视化 svg 图操作
在上一节进入交互式模式之后,执行web 命令时,可以查看 svg 图,如果遇到以下错误
failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in $PATH
说明需要安装 Graphviz。在mac上可以通过 brew install Graphviz 进行安装,并配置环境变量,在~/.zshrc中写入
export PATH="$PATH:/usr/local/Cellar/graphviz/2.40.1/bin"
其中2.40.1是版本号,随安装版本变化更改。写入文件之后保存,并执行source ~/.zshrc
额外说明一点,其中有依赖包可能需要安装svn,可以通过brew install svn进行安装
在交互模式下输入web 命令会自动下载 svg 文件,通过浏览器打开就可以看见图像
,大致如下

总结
- 对频繁分配的小对象,使用 sync.Pool 对象池避免分配
- 自动化的 DeepCopy 是非常耗时的,其中涉及到反射,内存分配,容器(如map)扩展等,大概比手动拷贝慢一个数量级
- 用 atomic.Load/StoreXXX,atomic.Value, sync.Map等代替 Mutex。
- (优先级递减) 使用高效的第三方库,如用fasthttp替代 net/http,github.com/gin-gonic/gin 代替 net/http/pprof
- 在开发环境加上-race编译选项进行竞态检查 在开发环境开启 net/http/pprof,方便实时 pprof
- 将所有外部IO(网络IO,磁盘IO)做成异步
本文介绍了Go语言中的pprof工具用于性能分析,包括runtime/pprof和net/http/pprof的使用,以及如何通过数据采样来监测CPU、内存等。通过web命令查看svg图进行可视化分析,并提供了解决Graphviz安装问题的提示,强调了性能优化的几点建议,如使用sync.Pool和避免DeepCopy等。
1095

被折叠的 条评论
为什么被折叠?



