• go cpu、内存监控、性能分析:PProf


    PProf

    PProf 是什么

    PProf是Go SDK内置的性能分析工具,用于分析和优化Go程序的性能。

    PProf通过收集和分析程序的运行时数据来生成性能分析报告。它使用Go语言的运行时特性,如代码注释和特殊的程序运行标记,来收集性能数据。PProf可以检测和测量程序中的CPU利用率、内存分配、阻塞等情况,并生成可视化的报告和图表,以帮助开发人员理解程序的行为和性能瓶颈。

    PProf 以 profile.proto 读取分析样本的集合,并生成报告以可视化并帮助分析数据(支持文本和图形报告)。 profile.proto 是一个 Protobuf v3 的描述文件,它描述了一组 callstack 和 symbolization 信息, 作用是统计分析的一组采样的调用栈,是很常见的 stacktrace 配置文件格式。

    有哪几种采样方式

    • runtime/pprof:采集程序(非 Server)的指定区块的运行数据进行分析。
    • net/http/pprof:基于 HTTP Server 运行,可以采集运行时数据进行分析。
    • go test:通过运行测试用例,并指定所需标识来进行采集。

    支持什么使用模式

    • Report generation:报告生成。
    • Interactive terminal use:交互式终端使用。
    • Web interface:Web 界面。

    可以做什么

    • CPU Profiling:CPU 分析,按照一定的频率采集所监听的应用程序 CPU(含寄存器)的使用情况,可确定应用程序在主动消耗 CPU 周期时花费时间的位置。
    • Memory Profiling:内存分析,在应用程序进行堆分配时记录堆栈跟踪,用于监视当前和历史内存使用情况,以及检查内存泄漏。
    • Block Profiling:阻塞分析,记录 Goroutine 阻塞等待同步(包括定时器通道)的位置,默认不开启,需要调用 runtime.SetBlockProfileRate 进行设置。
    • Mutex Profiling:互斥锁分析,报告互斥锁的竞争情况,默认不开启,需要调用 runtime.SetMutexProfileFraction 进行设置。
    • Goroutine Profiling: Goroutine 分析,可以对当前应用程序正在运行的 Goroutine 进行堆栈跟踪和分析。这项功能在实际排查中会经常用到,因为很多问题出现时的表象就是 Goroutine 暴增,而这时候我们要做的事情之一就是查看应用程序中的 Goroutine 正在做什么事情,因为什么阻塞了,然后再进行下一步。

    HTTP Server 使用举例

    1.代码

    提供一个http server,最重要一步,就是在 import 中添加 _ "net/http/pprof" 的引用

    1. import (
    2. "log"
    3. "net/http"
    4. "time"
    5. _ "net/http/pprof"
    6. )
    7. var datas []string
    8. func main() {
    9. go func() {
    10. for {
    11. log.Printf("len: %d", Add("go-programming-tour-book"))
    12. time.Sleep(time.Millisecond * 10)
    13. }
    14. }()
    15. _ = http.ListenAndServe("0.0.0.0:6060", nil)
    16. }
    17. func Add(str string) int {
    18. data := []byte(str)
    19. datas = append(datas, string(data))
    20. return len(datas)
    21. }

    启动程序,访问 http://127.0.0.1:6060/debug/pprof/ ,检查是否正常响应。 

    1.2 gin集成

    gin没有使用默认的DefaultServeMux,必须用正在使用的mux注册处理程序。

    可将 pprof 的路由绑定到默认端口,也可新开协程自定义pprof监听端口。

    1. // RegisterPprofRouter pprof路由组
    2. func RegisterPprofRouter(router *gin.Engine) {
    3. // 将 pprof 与路由器实例关联,绑定到web默认端口
    4. router.GET("/debug/pprof/*name", gin.WrapH(http.DefaultServeMux))
    5. // 也可自定义详细路由
    6. //router.GET("/", gin.WrapF(pprof.Index))
    7. //router.GET("/cmdline", gin.WrapF(pprof.Cmdline))
    8. //router.GET("/profile", gin.WrapF(pprof.Profile))
    9. //router.POST("/symbol", gin.WrapF(pprof.Symbol))
    10. //router.GET("/symbol", gin.WrapF(pprof.Symbol))
    11. //router.GET("/trace", gin.WrapF(pprof.Trace))
    12. //router.GET("/allocs", gin.WrapH(pprof.Handler("allocs")))
    13. //router.GET("/block", gin.WrapH(pprof.Handler("block")))
    14. //router.GET("/goroutine", gin.WrapH(pprof.Handler("goroutine")))
    15. //router.GET("/heap", gin.WrapH(pprof.Handler("heap")))
    16. //router.GET("/mutex", gin.WrapH(pprof.Handler("mutex")))
    17. //router.GET("/threadcreate", gin.WrapH(pprof.Handler("threadcreate")))
    18. }

     gin http server初始化:

    1. engine := gin.New()
    2. server = &http.Server{
    3. Addr: ":8080",
    4. Handler: engine,
    5. ReadTimeout: 30 * time.Second, // 读取请求的超时
    6. WriteTimeout: 90 * time.Second, // 读取请求+响应的超时(整个请求的超时)
    7. IdleTimeout: 60 * time.Second, // 等待下一个请求的超时
    8. MaxHeaderBytes: 1 << 20, // 请求头最大:1MB
    9. }

    2.浏览器访问

    访问 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 命令来分析文件。

    3.可视化界面分析profile文件

    1、文件下载

    1.浏览器页面直接下载:http://127.0.0.1:6060/debug/pprof/profile

    2.终端命令下载:wget http://127.0.0.1:6060/debug/pprof/profile

    3.可能存在网络隔离,可以服务器生成文件,再去下载服务器文件:

    1. curl http://localhost:6060/debug/pprof/profile > cpu.out
    2. curl http://localhost:6060/debug/pprof/heap > heap.out

    curl http://localhost:6060/debug/pprof/heap?seconds=60 > heap.out 

    2、文件分析

    本地执行终端命令:该命令将在所指定的端口号运行一个 PProf 分析用的站点。

    go tool pprof -http=:6001 profile文件 

    所有分析类型:

    1. go tool pprof http://localhost:8080/debug/pprof/allocs : 分析内存分配
    2. go tool pprof http://localhost:8080/debug/pprof/block : 分析堆栈跟踪导致阻塞的同步原语
    3. go tool pprof http://localhost:8080/debug/pprof/cmdline : 分析命令行调用的程序,web下调用报错
    4. go tool pprof http://localhost:8080/debug/pprof/goroutine : 分析当前 goroutine 的堆栈信息
    5. go tool pprof http://localhost:8080/debug/pprof/heap : 分析当前活动对象内存分配
    6. go tool pprof http://localhost:8080/debug/pprof/mutex : 分析堆栈跟踪竞争状态互斥锁的持有者
    7. go tool pprof http://localhost:8080/debug/pprof/profile : 分析一定持续时间内CPU的使用情况
    8. go tool pprof http://localhost:8080/debug/pprof/threadcreate : 分析堆栈跟踪系统新线程的创建
    9. go tool pprof http://localhost:8080/debug/pprof/trace : 分析追踪当前程序的执行状况

    如果出现错误提示 Could not execute dot; may need to install graphviz.,那么意味着你需要安装 graphviz 组件。参考 安装Graphviz

    3、文件内容

    通过 PProf 所提供的可视化界面,我们能够更方便、更直观的看到 Go 应用程序的调用链、使用情况等。另外在 View 菜单栏中,PProf 还支持多种分析方式的切换,如下:

    接下来我们将基于 CPU Profiling 所抓取的 Profile 进行一一介绍,而其它 Profile 类型的分析模式也是互通的,只要我们了解了一种,其余的也就会了。 

    Top

    • flat:函数自身的运行耗时。
    • flat%:函数自身在 CPU 运行耗时总比例。
    • sum%:函数自身累积使用 CPU 总比例。
    • cum:函数自身及其调用函数的运行总耗时。
    • cum%:函数自身及其调用函数的运行耗时总比例。
    • Name:函数名。

    在大多数的情况下,我们可以通过这五列得出一个应用程序的运行情况,知道当前是什么函数,正在做什么事情,占用了多少资源,谁又是占用资源的大头,以此来得到一个初步的分析方向。

    Graph

    该视图展示的为整体的函数调用流程,框越大、线越粗、框颜色越鲜艳(红色)就代表它占用的时间越久,开销越大。相反若框颜色越淡,越小则代表在整体的函数调用流程中,它的开销是相对较小的。

    因此我们可以用此视图去分析谁才是开销大头,它又是因为什么调用流程而被调用的。

    Flame Graph

     Flame Graph(火焰图)它是可动态的,调用顺序由上到下(A -> B -> C -> D),每一块代表一个函数、颜色越鲜艳(红)、区块越大代表占用 CPU 的时间更长。同时它也支持点击块深入进行分析,这样子我们就可以根据不同函数的多维度层级进行分析,能够更好的观察其流转并发现问题。

    Flame Graph(new)

    Peek

    此视图相较于 Top 视图,增加了所属的上下文信息的展示,也就是函数的输出调用者/被调用者。 

    Source

    该视图主要是增加了面向源代码的追踪和分析,可以看到其开销主要消耗在哪里。

    4.可视化界面分析trace文件

    trace文件下载到本地后,分析trace文件命令:

    go tool trace -http=:6002 trace文件
    Event timelines for running goroutines

    运行 goroutine 的事件时间线。

    View trace 查看踪迹

    该视图显示每个 GOMAXPROCS 逻辑处理器的时间线,显示每个时刻哪个 goroutine(如果有)在该逻辑处理器上运行。

    Goroutine analysis Goroutine分析

    该视图显示有关共享相同 main 函数的每组 goroutine 的信息。

    Profiles

    配置文件。

    网络阻止配置文件
    同步阻塞配置文件
    系统调用阻止配置文件
    调度程序延迟配置文件

    User-defined tasks and regions

    用户定义的任务和区域。

    Garbage collection metrics

    垃圾收集指标。

    该图显示了最大GC暂停时间(y为零时的最大x值),更一般地说,在最坏的情况下,对于指定大小的任何时间窗口,处理器可用于应用程序例程(“mutators”)的时间比例。

    安装Graphviz

    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

    测试代码 

    1. var yzhString = "yzh测试!!!Hahahahaahahahah哈哈哈哈哈哈哈"
    2. var yzhList []byte
    3. func Add(str []byte) int {
    4. if len(yzhList) > 10485760 { //最大10M
    5. return len(yzhList)
    6. }
    7. yzhList = append(yzhList, str...)
    8. return len(yzhList)
    9. }
    10. func Init() {
    11. //test代码
    12. go func() {
    13. for {
    14. Add([]byte(yzhString))
    15. //logger.Infof("len:%v", Add([]byte(yzhString)))
    16. time.Sleep(time.Millisecond * 10)
    17. }
    18. }()
    19. }

    参考

    Go 大杀器之性能剖析 PProf(上) | Go 语言编程之旅

    golang pprof实用使用指南 - 掘金

    https://github.com/google/pprof/blob/main/doc/README.md

    https://go.dev/blog/pprof

  • 相关阅读:
    动态代理:一种灵活的设计模式
    PAT 1019 General Palindromic Number
    ADPCM(自适应差分脉冲编码调制)的原理和计算
    机器学习之模拟退火算法
    matlab小波分析时频谱图 声音时频信号处理
    学生用什么台灯最好?分享专业的学生护眼台灯
    ASP .NET Core API(swaggerUI)实例demo下载、发布与部署(各种遇到的坑、解决方法)
    【季报分析】百度2022年Q3:逆势而上
    110.网络安全渗透测试—[权限提升篇8]—[Windows SqlServer xp_cmdshell存储过程提权]
    理解ASP.NET Core - 发送Http请求(HttpClient)
  • 原文地址:https://blog.csdn.net/yzh_1346983557/article/details/133797937