golang 性能调优分析工具 pprof (上)

一、golang 程序性能调优 在 golang 程序中,有哪些内容需要调试优化?

一般常规内容:

cpu:程序对cpu的使用情况 - 使用时长,占比等

内存:程序对cpu的使用情况 - 使用时长,占比,内存泄露等。如果在往里分,程序堆、栈使用情况

I/O:IO的使用情况 - 哪个程序IO占用时间比较长

golang 程序中:

goroutine:go的协程使用情况,调用链的情况

goroutine leak:goroutine泄露检查

go dead lock:死锁的检测分析

data race detector:数据竞争分析,其实也与死锁分析有关

上面是在 golang 程序中,性能调优的一些内容。

有什么方法工具调试优化 golang 程序?

比如 linux 中 cpu 性能调试,工具有 top,dstat,perf 等。

那么在 golang 中,有哪些分析方法?

golang 性能调试优化方法:

Benchmark基准测试,对特定代码的运行时间和内存信息等进行测试

Profiling程序分析,程序的运行画像,在程序执行期间,通过采样收集的数据对程序进行分析

Trace跟踪,在程序执行期间,通过采集发生的事件数据对程序进行分析

profiling 和 trace 有啥区别?
profiling 分析没有时间线,trace 分析有时间线。

在 golang 中,应用方法的工具呢?

这里介绍 pprof 这个 golang 工具,它可以帮助我们调试优化程序。

它的最原始程序是 gperftools - https://github.com/gperftools/gperftools,golang 的 pprof 是从它而来的。

二、pprof 介绍 简介

pprof 是 golang 官方提供的性能调优分析工具,可以对程序进行性能分析,并可视化数据,看起来相当的直观。
当你的 go 程序遇到性能瓶颈时,可以使用这个工具来进行调试并优化程序。

本文将对下面 golang 中 2 个监控性能的包 pprof 进行运用:

runtime/pprof:采集程序运行数据进行性能分析,一般用于后台工具型应用。

net/http/pprof:对 runtime/pprof 的二次封装,一般应用于 http server ,采集 http server 运行时数据进行分析。

pprof 开启后,每隔一段时间就会采集当前程序的堆栈信息,获取函数的 cpu、内存等使用情况。通过对采样的数据进行分析,形成一个数据分析报告。

pprof 以 profile.proto 的格式保存数据,然后根据这个数据生成可视化的分析报告,支持文本形式和图形形式报告。
profile.proto 里具体的数据格式是 protocol buffers。

pprof 使用模式

Report generation:报告生成

Interactive terminal use:交互式终端

Web interface:Web 界面

三、runtime/pprof 前提条件

先安装 pprof: go get -u github.com/google/pprof。

调试分析 golang 程序,要开启 profile 然后开始采样数据。

采样数据的方式:

第 1 种,在 go 程序中添加如下代码:
为当前 process 开启 CPU profiling 。
停止当前的 CPU profile。当所有的 profile 写完了后它才返回。

// 开启 cpu 采集分析: pprof.StartCPUProfile(w io.Writer) // 停止 cpu 采集分析: pprof.StopCPUProfile()

把内存 heap 相关的内容写入到文件中

pprof.WriteHeapProfile(w io.Writer)

第 2 种,在 benchmark 测试的时候

go test -cpuprofile cpu.prof -memprofile mem.prof -bench .

还有一种,对 http server 采集数据

go tool pprof $host/debug/pprof/profile 程序示例

go version go1.13.9

例子 1

我们用第 1 种方法,在程序中添加分析代码,demo.go :

package main import ( "bytes" "flag" "log" "math/rand" "os" "runtime" "runtime/pprof" "sync" ) var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") var memprofile = flag.String("memprofile", "", "write mem profile to `file`") func main() { flag.Parse() if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal("could not create CPU profile: ", err) } defer f.Close() if err := pprof.StartCPUProfile(f); err != nil { log.Fatal("could not start CPU profile: ", err) } defer pprof.StopCPUProfile() } var wg sync.WaitGroup wg.Add(200) for i := 0; i < 200; i++ { go cyclenum(30000, &wg) } writeBytes() wg.Wait() if *memprofile != "" { f, err := os.Create(*memprofile) if err != nil { log.Fatal("could not create memory profile: ", err) } defer f.Close() runtime.GC() if err := pprof.WriteHeapProfile(f); err != nil { log.Fatal("cound not write memory profile: ", err) } } } func cyclenum(num int, wg *sync.WaitGroup) { slice := make([]int, 0) for i := 0; i < num; i++ { for j := 0; j < num; j++ { j = i + j slice = append(slice, j) } } wg.Done() } func writeBytes() *bytes.Buffer { var buff bytes.Buffer for i := 0; i < 30000; i++ { buff.Write([]byte{'0' + byte(rand.Intn(10))}) } return &buff }

编译程序、采集数据、分析程序:

编译 demo.go

go build demo.go

用 pprof 采集数据,命令如下:

./demo.exe --cpuprofile=democpu.pprof --memprofile=demomem.pprof

说明:我是 win 系统,这个 demo 就是 demo.exe ,linux 下是 demo

分析数据,命令如下:

go tool pprof democpu.pprof

go tool pprof 简单的使用格式为:go tool pprof [binary] [source]

binary: 是应用的二进制文件,用来解析各种符号

source: 表示 profile 数据的来源,可以是本地的文件,也可以是 http 地址

要了解 go tool pprof 更多命令使用方法,请查看文档:go tool pprof --help

注意

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsxzwp.html