go:pprof 性能分析

什么是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/

可以得到以下内容
go:pprof 性能分析_第1张图片
可以直接点击上面的链接,进入子页面,查看相关的汇总信息

点击 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 文件,通过浏览器打开就可以看见图像
,大致如下
go:pprof 性能分析_第2张图片

总结

  • 对频繁分配的小对象,使用 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
  • go pprof 性能分析
  • Golang 大杀器之性能剖析 PProf

你可能感兴趣的:(go,golang,服务器)