概述

pprof 是用于可视化和分析性能分析数据的工具
CPU Profiling:CPU 分析,按照一定的频率采集所监听的应用程序 CPU(含寄存器)的使用情况,可确定应用程序在主动消耗 CPU 周期时花费时间的位置
Memory Profiling:内存分析,在应用程序进行堆分配时记录堆栈跟踪,用于监视当前和历史内存使用情况,以及检查内存泄漏
Block Profiling:阻塞分析,记录 goroutine 阻塞等待同步(包括定时器通道)的位置
Mutex Profiling:互斥锁分析,报告互斥锁的竞争情况。
Go语言内置了获取程序的运行数据的工具,包括以下两个标准库:

  • runtime/pprof:采集工具型应用运行数据进行分析
  • net/http/pprof:采集web应用运行时数据进行分析

注意:获取的 Profiling 数据是动态的,要想获得有效的数据,请保证应用处于较大的负载(比如正在生成中运行的服务,或者通过其他工具模拟访问压力)。否则如果应用处于空闲状态,得到的结果可能没有任何意义。

runtime/pprof

CUP分析

开启CPU性能分析:

  1. pprof.StartCPUProfile(file)

停止CPU性能分析

  1. pprof.StopCPUProfile()

应用执行结束后,就会生成一个文件,保存了我们的 CPU profiling 数据。得到采样数据之后,使用go tool pprof工具进行CPU性能分析。

内存分析

记录程序的堆栈信息

  1. pprof.WriteHeapProfile(file)

net/http/pprof

安装graphviz

https://graphviz.gitlab.io/download/
mac 推荐使用brew

  1. brew install graphviz

Linux安装

  1. # Ubuntu
  2. sudo apt-get install graphviz
  3. # Centos
  4. yum install graphviz

检查是否安装成功

  1. dot -version
  1. package main
  2. import (
  3. "net/http"
  4. "log"
  5. _ "net/http/pprof"
  6. )
  7. func main() {
  8. http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
  9. writer.Write([]byte("hello world"))
  10. })
  11. log.Fatal(http.ListenAndServe(":8080", nil))
  12. }

执行下面的命令 开启服务,监听8080

  1. go run main.go

打开监控界面 http://localhost:8080/debug/pprof/,或者使用下面单独接口
cpu(CPU Profiling): HOST/debug/pprof/profile,默认进行 30s 的 CPU Profiling,得到一个分析用的 profile 文件
block(Block Profiling):HOST/debug/pprof/block,查看导致阻塞同步的堆栈跟踪
goroutine:HOST/debug/pprof/goroutine,查看当前所有运行的 goroutines 堆栈跟踪
heap(Memory Profiling): HOST/debug/pprof/heap,查看活动对象的内存分配情况
mutex(Mutex Profiling):HOST/debug/pprof/mutex,查看导致互斥锁的竞争持有者的堆栈跟踪
threadcreate:HOST/debug/pprof/threadcreate,查看创建新OS线程的堆栈跟踪

image.png

allocs:所有过去内存分配的采样
block:导致同步原语阻塞的堆栈跟踪
cmdline:当前程序的命令行调用
goroutine:所有当前goroutine的堆栈跟踪
heap:活动对象的内存分配的采样。在获取堆样本之前,可以指定gc GET参数来运行gc。
metux:争用互斥锁持有者的堆栈跟踪
profile:CPU配置文件。您可以在seconds GET参数中指定持续时间。获取配置文件后,使用go tool pprof命令调查配置文件
threadcreate:导致创建新操作系统线程的堆栈跟踪
trace:当前程序的执行轨迹。您可以在seconds GET参数中指定持续时间。获取跟踪文件后,使用go tool trace命令调查跟踪

go tool命令


不管是工具型应用还是服务型应用,我们使用相应的pprof库获取数据之后,下一步的都要对这些数据进行分析,我们可以使用go tool pprof命令行工具。

pprof

go tool pprof profile文件名, 此时会进入一个交互式控制台,输入命令 web会产生一个svg文件,程序回启动浏览器自动打开这个文件,即可进入可视化界面。我们也可以在上面CPU分析中的控制台中以同样的方式进入可视化界面。

  1. go tool pprof http://localhost:8080/debug/pprof/profile\?seconds\=60
  2. Fetching profile over HTTP from http://localhost:8080/debug/pprof/profile?seconds=60
  3. Saved profile in /Users/baxiang/pprof/pprof.samples.cpu.001.pb.gz
  4. Type: cpu
  5. Time: Apr 3, 2019 at 12:20am (CST)
  6. Duration: 1mins, Total samples = 1.08mins (107.69%)
  7. Entering interactive mode (type "help" for commands, "o" for options)
  8. (pprof) top10
  9. Showing nodes accounting for 61.29s, 94.69% of 64.73s total
  10. Dropped 55 nodes (cum <= 0.32s)
  11. Showing top 10 nodes out of 43
  12. flat flat% sum% cum cum%
  13. 20.93s 32.33% 32.33% 21.72s 33.55% runtime.bulkBarrierPreWrite
  14. 10.35s 15.99% 48.32% 10.35s 15.99% runtime.memclrNoHeapPointers
  15. 8.58s 13.26% 61.58% 8.58s 13.26% runtime.usleep
  16. 8.02s 12.39% 73.97% 8.82s 13.63% runtime.scanobject
  17. 6.19s 9.56% 83.53% 6.19s 9.56% runtime.memmove
  18. 3.60s 5.56% 89.09% 44.64s 68.96% main.main.func1
  19. 1.39s 2.15% 91.24% 1.39s 2.15% runtime.mach_semaphore_timedwait
  20. 1.07s 1.65% 92.89% 3.02s 4.67% runtime.notetsleep
  21. 0.59s 0.91% 93.81% 0.59s 0.91% runtime.heapBits.bits (inline)
  22. 0.57s 0.88% 94.69% 0.61s 0.94% runtime.heapBitsSetType
  23. (pprof)

go tool pprof -http=:8080 profile文件名 ,此时浏览器会默认打开localhost:8080访问 ,建议使用这种方式,获取更好体验。

  1. $ go tool pprof -http=:8090 profile

image.png
go tool trace

火焰图

已经集成到go tool
下载安装:

  1. go get -u github.com/google/pprof

go-torch

go-torch是urbe开源的,现在这个项目已经废弃不维护了 直接建议使用pprof
image.png

ginpprof

https://github.com/gin-contrib/pprof
使用 https://github.com/DeanThompson/ginpprof

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "github.com/DeanThompson/ginpprof"
  5. )
  6. func main() {
  7. router := gin.Default()
  8. router.GET("/ping", func(c *gin.Context) {
  9. c.JSON(200,gin.H{"data":"ping"})
  10. })
  11. ginpprof.Wrap(router)
  12. router.Run(":8080")
  13. }

运行

  1. $ go run main.go
  2. [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
  3. [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
  4. - using env: export GIN_MODE=release
  5. - using code: gin.SetMode(gin.ReleaseMode)
  6. [GIN-debug] GET /ping --> main.main.func1 (3 handlers)
  7. [GIN-debug] GET /debug/pprof/ --> github.com/DeanThompson/ginpprof.IndexHandler.func1 (3 handlers)
  8. [GIN-debug] GET /debug/pprof/heap --> github.com/DeanThompson/ginpprof.HeapHandler.func1 (3 handlers)
  9. [GIN-debug] GET /debug/pprof/goroutine --> github.com/DeanThompson/ginpprof.GoroutineHandler.func1 (3 handlers)
  10. [GIN-debug] GET /debug/pprof/allocs --> github.com/DeanThompson/ginpprof.AllocsHandler.func1 (3 handlers)
  11. [GIN-debug] GET /debug/pprof/block --> github.com/DeanThompson/ginpprof.BlockHandler.func1 (3 handlers)
  12. [GIN-debug] GET /debug/pprof/threadcreate --> github.com/DeanThompson/ginpprof.ThreadCreateHandler.func1 (3 handlers)
  13. [GIN-debug] GET /debug/pprof/cmdline --> github.com/DeanThompson/ginpprof.CmdlineHandler.func1 (3 handlers)
  14. [GIN-debug] GET /debug/pprof/profile --> github.com/DeanThompson/ginpprof.ProfileHandler.func1 (3 handlers)
  15. [GIN-debug] GET /debug/pprof/symbol --> github.com/DeanThompson/ginpprof.SymbolHandler.func1 (3 handlers)
  16. [GIN-debug] POST /debug/pprof/symbol --> github.com/DeanThompson/ginpprof.SymbolHandler.func1 (3 handlers)
  17. [GIN-debug] GET /debug/pprof/trace --> github.com/DeanThompson/ginpprof.TraceHandler.func1 (3 handlers)
  18. [GIN-debug] GET /debug/pprof/mutex --> github.com/DeanThompson/ginpprof.MutexHandler.func1 (3 handlers)

执行 http://127.0.0.1:8080/debug/pprof/

go-wrk

安装go-wrk 进入到GOPATH/src/github

  1. $ cd $GOPATH/src/github.com
  2. $ mkdir tsliwowicz
  3. $ cd tsliwowicz
  4. $ git clone https://github.com/tsliwowicz/go-wrk.git
  5. $ cd go-wrk
  6. $ go install go-wrk.go

go-wrk常用命令

  1. $ go-wrk -help
  2. Usage: go-wrk <options> <url>
  3. Options:
  4. -H header line, joined with ';' (Default )
  5. -M HTTP method (Default GET)
  6. -T Socket/request timeout in ms (Default 1000)
  7. -body request body string or @filename (Default )
  8. -c Number of goroutines to use (concurrent connections) (Default 10)
  9. -ca CA file to verify peer against (SSL/TLS) (Default )
  10. -cert CA certificate file to verify peer against (SSL/TLS) (Default )
  11. -d Duration of test in seconds (Default 10)
  12. -f Playback file name (Default <empty>)
  13. -help Print help (Default false)
  14. -host Host Header (Default )
  15. -http Use HTTP/2 (Default true)
  16. -key Private key file name (SSL/TLS (Default )
  17. -no-c Disable Compression - Prevents sending the "Accept-Encoding: gzip" header (Default false)
  18. -no-ka Disable KeepAlive - prevents re-use of TCP connections between different HTTP requests (Default false)
  19. -redir Allow Redirects (Default false)
  20. -v Print version details (Default false)

测试,开启50并发 5秒 查看请求结果性能

  1. $ go-wrk -c 50 -d 5 http://127.0.0.1:8080/ping
  2. Running 5s test @ http://127.0.0.1:8080/ping
  3. 50 goroutine(s) running concurrently
  4. 16436 requests in 5.000469347s, 1.91MB read
  5. Requests/sec: 3286.89
  6. Transfer/sec: 391.60KB
  7. Avg Req Time: 15.211941ms
  8. Fastest Request: 165.578µs
  9. Slowest Request: 432.370243ms
  10. Number of Errors: 0

参考文章

Golang 大杀器之性能剖析 PProf
深度解密Go语言之pprof
https://www.jianshu.com/p/9c6e4cc94dda