PProf是Go SDK内置的性能分析工具,用于分析和优化Go程序的性能。
PProf通过收集和分析程序的运行时数据来生成性能分析报告。它使用Go语言的运行时特性,如代码注释和特殊的程序运行标记,来收集性能数据。PProf可以检测和测量程序中的CPU利用率、内存分配、阻塞等情况,并生成可视化的报告和图表,以帮助开发人员理解程序的行为和性能瓶颈。
PProf 以 profile.proto 读取分析样本的集合,并生成报告以可视化并帮助分析数据(支持文本和图形报告)。 profile.proto 是一个 Protobuf v3 的描述文件,它描述了一组 callstack 和 symbolization 信息, 作用是统计分析的一组采样的调用栈,是很常见的 stacktrace 配置文件格式。
runtime.SetBlockProfileRate
进行设置。runtime.SetMutexProfileFraction
进行设置。提供一个http server,最重要一步,就是在 import 中添加 _ "net/http/pprof" 的引用
- import (
- "log"
- "net/http"
- "time"
-
- _ "net/http/pprof"
- )
-
- var datas []string
-
- func main() {
- go func() {
- for {
- log.Printf("len: %d", Add("go-programming-tour-book"))
- time.Sleep(time.Millisecond * 10)
- }
- }()
-
- _ = http.ListenAndServe("0.0.0.0:6060", nil)
- }
-
- func Add(str string) int {
- data := []byte(str)
- datas = append(datas, string(data))
- return len(datas)
- }
启动程序,访问 http://127.0.0.1:6060/debug/pprof/ ,检查是否正常响应。
gin没有使用默认的DefaultServeMux,必须用正在使用的mux注册处理程序。
可将 pprof 的路由绑定到默认端口,也可新开协程自定义pprof监听端口。
- // RegisterPprofRouter pprof路由组
- func RegisterPprofRouter(router *gin.Engine) {
- // 将 pprof 与路由器实例关联,绑定到web默认端口
- router.GET("/debug/pprof/*name", gin.WrapH(http.DefaultServeMux))
- // 也可自定义详细路由
- //router.GET("/", gin.WrapF(pprof.Index))
- //router.GET("/cmdline", gin.WrapF(pprof.Cmdline))
- //router.GET("/profile", gin.WrapF(pprof.Profile))
- //router.POST("/symbol", gin.WrapF(pprof.Symbol))
- //router.GET("/symbol", gin.WrapF(pprof.Symbol))
- //router.GET("/trace", gin.WrapF(pprof.Trace))
- //router.GET("/allocs", gin.WrapH(pprof.Handler("allocs")))
- //router.GET("/block", gin.WrapH(pprof.Handler("block")))
- //router.GET("/goroutine", gin.WrapH(pprof.Handler("goroutine")))
- //router.GET("/heap", gin.WrapH(pprof.Handler("heap")))
- //router.GET("/mutex", gin.WrapH(pprof.Handler("mutex")))
- //router.GET("/threadcreate", gin.WrapH(pprof.Handler("threadcreate")))
- }
gin http server初始化:
- engine := gin.New()
- server = &http.Server{
- Addr: ":8080",
- Handler: engine,
- ReadTimeout: 30 * time.Second, // 读取请求的超时
- WriteTimeout: 90 * time.Second, // 读取请求+响应的超时(整个请求的超时)
- IdleTimeout: 60 * time.Second, // 等待下一个请求的超时
- MaxHeaderBytes: 1 << 20, // 请求头最大:1MB
- }
访问 http://127.0.0.1:6060/debug/pprof/ ,页面如下:
allocs: 内存分配的采样信息
block: 同步阻塞的堆栈跟踪的采样信息
cmdline: 程序启动命令及参数
goroutine: 当前所有协程的堆栈跟踪
heap: 堆内存的对象的采样信息。可指定 gc GET 参数以在获取样本之前运行 GC。
mutex: 互斥锁持有者的堆栈跟踪的采样信息
profile: CPU 占用情况的采样信息。默认进行 30s 的 CPU Profiling,得到一个分析用的 profile 文件。您可以在 GET 参数中指定持续时间。获取配置文件后,使用 go tool pprof 命令来分析文件。
threadcreate: 创建操作系统线程的堆栈跟踪的采样信息
trace: 当前程序的执行轨迹。您可以在秒 GET 参数中指定持续时间。获取跟踪文件后,使用 go tool trace 命令来分析文件。
1.浏览器页面直接下载:http://127.0.0.1:6060/debug/pprof/profile
2.终端命令下载:wget http://127.0.0.1:6060/debug/pprof/profile
3.可能存在网络隔离,可以服务器生成文件,再去下载服务器文件:
- curl http://localhost:6060/debug/pprof/profile > cpu.out
- curl http://localhost:6060/debug/pprof/heap > heap.out
curl http://localhost:6060/debug/pprof/heap?seconds=60 > heap.out
本地执行终端命令:该命令将在所指定的端口号运行一个 PProf 分析用的站点。
go tool pprof -http=:6001 profile文件
所有分析类型:
- go tool pprof http://localhost:8080/debug/pprof/allocs : 分析内存分配
- go tool pprof http://localhost:8080/debug/pprof/block : 分析堆栈跟踪导致阻塞的同步原语
- go tool pprof http://localhost:8080/debug/pprof/cmdline : 分析命令行调用的程序,web下调用报错
- go tool pprof http://localhost:8080/debug/pprof/goroutine : 分析当前 goroutine 的堆栈信息
- go tool pprof http://localhost:8080/debug/pprof/heap : 分析当前活动对象内存分配
- go tool pprof http://localhost:8080/debug/pprof/mutex : 分析堆栈跟踪竞争状态互斥锁的持有者
- go tool pprof http://localhost:8080/debug/pprof/profile : 分析一定持续时间内CPU的使用情况
- go tool pprof http://localhost:8080/debug/pprof/threadcreate : 分析堆栈跟踪系统新线程的创建
- go tool pprof http://localhost:8080/debug/pprof/trace : 分析追踪当前程序的执行状况
如果出现错误提示 Could not execute dot; may need to install graphviz.,那么意味着你需要安装 graphviz 组件。参考 安装Graphviz
通过 PProf 所提供的可视化界面,我们能够更方便、更直观的看到 Go 应用程序的调用链、使用情况等。另外在 View 菜单栏中,PProf 还支持多种分析方式的切换,如下:
接下来我们将基于 CPU Profiling 所抓取的 Profile 进行一一介绍,而其它 Profile 类型的分析模式也是互通的,只要我们了解了一种,其余的也就会了。
在大多数的情况下,我们可以通过这五列得出一个应用程序的运行情况,知道当前是什么函数,正在做什么事情,占用了多少资源,谁又是占用资源的大头,以此来得到一个初步的分析方向。
该视图展示的为整体的函数调用流程,框越大、线越粗、框颜色越鲜艳(红色)就代表它占用的时间越久,开销越大。相反若框颜色越淡,越小则代表在整体的函数调用流程中,它的开销是相对较小的。
因此我们可以用此视图去分析谁才是开销大头,它又是因为什么调用流程而被调用的。
Flame Graph(火焰图)它是可动态的,调用顺序由上到下(A -> B -> C -> D),每一块代表一个函数、颜色越鲜艳(红)、区块越大代表占用 CPU 的时间更长。同时它也支持点击块深入进行分析,这样子我们就可以根据不同函数的多维度层级进行分析,能够更好的观察其流转并发现问题。
Flame Graph(new)
此视图相较于 Top 视图,增加了所属的上下文信息的展示,也就是函数的输出调用者/被调用者。
该视图主要是增加了面向源代码的追踪和分析,可以看到其开销主要消耗在哪里。
trace文件下载到本地后,分析trace文件命令:
go tool trace -http=:6002 trace文件
运行 goroutine 的事件时间线。
该视图显示每个 GOMAXPROCS 逻辑处理器的时间线,显示每个时刻哪个 goroutine(如果有)在该逻辑处理器上运行。
该视图显示有关共享相同 main 函数的每组 goroutine 的信息。
配置文件。
网络阻止配置文件
同步阻塞配置文件
系统调用阻止配置文件
调度程序延迟配置文件
用户定义的任务和区域。
垃圾收集指标。
该图显示了最大GC暂停时间(y为零时的最大x值),更一般地说,在最坏的情况下,对于指定大小的任何时间窗口,处理器可用于应用程序例程(“mutators”)的时间比例。
1、安装Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
官网地址:Homebrew — The Missing Package Manager for macOS (or Linux)
2、安装graphviz程序。
brew install graphviz
- var yzhString = "yzh测试!!!Hahahahaahahahah哈哈哈哈哈哈哈"
- var yzhList []byte
-
- func Add(str []byte) int {
- if len(yzhList) > 10485760 { //最大10M
- return len(yzhList)
- }
- yzhList = append(yzhList, str...)
- return len(yzhList)
- }
-
- func Init() {
- //test代码
- go func() {
- for {
- Add([]byte(yzhString))
- //logger.Infof("len:%v", Add([]byte(yzhString)))
- time.Sleep(time.Millisecond * 10)
- }
- }()
- }
Go 大杀器之性能剖析 PProf(上) | Go 语言编程之旅