美文网首页
go包:pprof调试器的使用

go包:pprof调试器的使用

作者: 呦丶耍脾气 | 来源:发表于2023-07-05 11:19 被阅读0次

    1. 调用图说明

    1.1 示例图

    image.png

    1.2 节点颜色

    • 红色代表累计值cum为正,并且很大;
    • 绿色代表累计值cum为负,并且很大;
    • 灰色代表累计值cum可以忽略不计。

    1.3 节点字体大小

    • 较大的字体表示较大的当前值;
    • 较小的字体表示较小的当前值。

    1.4 边框颜色

    • 当前值较大并且为正数时为红色;
    • 当前值较小并且为负数时为绿色;
    • 接近0的当前值为灰色。

    1.5 箭头大小

    • 箭头越粗代表当前的路径消耗了越多的资源;
    • 箭头越细代表当前的路径消耗了越少的资源。

    1.6 箭头类型

    • 虚线箭头表示两个节点之间的某些节点已被忽略,为间接调用;
    • 实线箭头表示两个节点之间为直接调用。

    2. 火焰图说明

    2.1 示例图

    image.png

    2.2 含义说明

    • 最上方的root框代表整个程序的开始,其他的框都代表一个函数。
    • 火焰图每一层中的函数都是平级的,下层函数是其对应的上层函数的子函数。
    • 函数调用栈越长,火焰就越高。
    • 框越长、颜色越深,代表当前函数占用资源越多。
    • 可以单击任何框,查看该函数更详细的信息。

    **排查三步曲: **top: 根据资源排序; list:查看具体代码信息;web:在浏览器中打开调用图

    3. 排查内存占用高

    3.1 进入交互式

    # 这里的app是编译后的文件名
    ➜ go tool pprof app http://127.0.0.1:6060/debug/pprof/heap
    Fetching profile over HTTP from http://127.0.0.1:6060/debug/pprof/heap
    Saved profile in /Users/liuqh/pprof/pprof.app.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
    File: app
    Type: inuse_space
    Time: Nov 16, 2021 at 9:14pm (CST)
    Entering interactive mode (type "help" for commands, "o" for options)
    

    3.2 定位内存最高

    (pprof) top
    Showing nodes accounting for 5290.49kB, 100% of 5290.49kB total
          flat  flat%   sum%        cum   cum%
     3754.47kB 70.97% 70.97%  5290.49kB   100%  52lu/go-pprof/scenes.UseHeapDemo.func1
     1536.02kB 29.03%   100%  1536.02kB 29.03%  fmt.Sprintf
             0     0%   100%   512.01kB  9.68%  52lu/go-pprof/scenes.getBody
             0     0%   100%  1024.02kB 19.36%  52lu/go-pprof/scenes.getGirl
    

    3.3 查看具体代码

    (pprof) list UseHeapDemo
    Total: 5.17MB
    ROUTINE ======================== 52lu/go-pprof/scenes.UseHeapDemo.func1 in /Users/liuqh/ProjectItem/GoItem/go-pprof/scenes/heap.go
        3.67MB     5.17MB (flat, cum)   100% of Total
             .          .      8:func UseHeapDemo()  {
             .          .      9:    go func() {
             .          .     10:        var result []string
             .          .     11:        i := 1
             .          .     12:        for {
             .   512.01kB     13:            body := getBody()
             .        1MB     14:            girl := getGirl()
             .          .     15:            result = append(result,body...)
        3.67MB     3.67MB     16:            result = append(result,girl...)
             .          .     17:            fmt.Printf("第%d轮,count:%v \n",i,len(result))
             .          .     18:            time.Sleep(time.Second * 5)
             .          .     19:            i++
             .          .     20:        }
             .          .     21:    }()
    (pprof)
    

    3.4 在浏览器中查看

    (pprof) web
    

    4. 排查CPU占用高

    4.1 进入交互式

    # 这里的app是编译后的文件名
    ➜ go tool pprof app http://127.0.0.1:6060/debug/pprof/profile
    Fetching profile over HTTP from http://127.0.0.1:6060/debug/pprof/profile
    Saved profile in /Users/liuqh/pprof/pprof.app.samples.cpu.003.pb.gz
    File: app
    Type: cpu
    Time: Nov 16, 2021 at 8:55pm (CST)
    Duration: 30s, Total samples = 15.76s (52.53%)
    Entering interactive mode (type "help" for commands, "o" for options)
    (pprof)
    

    4.2 定位cpu占用最高

    (pprof) top
    Showing nodes accounting for 15.68s, 99.49% of 15.76s total 
    Dropped 9 nodes (cum <= 0.08s)
    flat  flat%   sum%        cum   cum%
    15.44s 97.97% 97.97%     15.68s 99.49%  52lu/go-pprof/scenes.compute
    0.24s  1.52% 99.49%      0.24s  1.52%  runtime.asyncPreempt
    0     0% 99.49%     15.68s 99.49%  52lu/go-pprof/scenes.UseCpuDemo (inline)
    0     0% 99.49%     15.68s 99.49%  main.main
    0     0% 99.49%      0.08s  0.51%  runtime.findrunnable
    0     0% 99.49%     15.68s 99.49%  runtime.main
    0     0% 99.49%      0.08s  0.51%  runtime.mcall
    0     0% 99.49%      0.08s  0.51%  runtime.park_m
    0     0% 99.49%      0.08s  0.51%  runtime.schedule
    

    4.3 查看具体代码

    (pprof) list compute
    Total: 15.76s
    ROUTINE ======================== 52lu/go-pprof/scenes.compute in /Users/liuqh/ProjectItem/GoItem/go-pprof/scenes/cpu.go
        15.44s     15.68s (flat, cum) 99.49% of Total
             .          .      6:    compute()
             .          .      7:}
             .          .      8:
             .          .      9:func compute()  {
             .          .     10:    var total int64
        15.44s     15.68s     11:    for i := 0; i < 100000000000; i++ {
             .          .     12:        total = total + int64(i)
             .          .     13:    }
             .          .     14:    fmt.Println("遍历完成")
             .          .     15:}
    

    4.4 在浏览器中查看

    (pprof) web
    

    @注:需要安装graphviz

    5. 排查协程泄露

    分析协程栈有两方面的作用,一是查看协程的数量,查看协程是否泄漏。二是查看当前大量的协程在执行哪些函数,判断当前协程是否健康。

    5.1 什么是协程泄露

    Go的并发是以goroutinechannel的形式实现的。协程泄露是指goroutine创建后,长时间得不到释放,并且还在不断地创建新的goroutine协程,最终导致内存耗尽,程序崩溃。

    5.2 进入交互式

    ➜ go tool pprof app http://127.0.0.1:6060/debug/pprof/goroutine
    Fetching profile over HTTP from http://127.0.0.1:6060/debug/pprof/goroutine
    Saved profile in /Users/liuqh/pprof/pprof.app.goroutine.007.pb.gz
    File: app
    Type: goroutine
    Time: Nov 16, 2021 at 9:43pm (CST)
    Entering interactive mode (type "help" for commands, "o" for options)
    

    5.3 定位协程情况

    (pprof) top
    Showing nodes accounting for 37, 100% of 37 total # 收集到37个协程
    Showing top 10 nodes out of 41
          flat  flat%   sum%        cum   cum%
            35 94.59% 94.59%         35 94.59%  runtime.gopark
             1  2.70% 97.30%          1  2.70%  net/http.(*connReader).backgroundRead
             1  2.70%   100%          1  2.70%  runtime/pprof.runtime_goroutineProfileWithLabels
             0     0%   100%          1  2.70%  52lu/go-pprof/scenes.UseGoroutineDemo
             0     0%   100%          1  2.70%  52lu/go-pprof/scenes.errorUse
             0     0%   100%         30 81.08%  52lu/go-pprof/scenes.errorUse.func1
             0     0%   100%          3  8.11%  bufio.(*Reader).ReadLine
             0     0%   100%          3  8.11%  bufio.(*Reader).ReadSlice
             0     0%   100%          3  8.11%  bufio.(*Reader).fill
             0     0%   100%          1  2.70%  internal/poll.(*FD).Accep
    

    分析:

    从上面看到有35个协程都在runtime.gopark函数,runtime.gopark:代表协程处于休眠状态,其中有30个协程是由scenes.errorUse.func1产出。

    5.4 查看具体代码

    (pprof) list errorUse.func1
    Total: 37
    ROUTINE ======================== 52lu/go-pprof/scenes.errorUse.func1 in /Users/liuqh/ProjectItem/GoItem/go-pprof/scenes/goroutine.go
             0         30 (flat, cum) 81.08% of Total
             .          .      9:
             .          .     10:func errorUse()  {
             .          .     11:    for  {
             .          .     12:        time.Sleep(time.Second)
             .          .     13:        go func() {
             .         30     14:            time.Sleep(time.Second * 30)
             .          .     15:        }()
             .          .     16:    }
             .          .     17:}
             .          .     18:func trueUse()  {
             .          .     19:    res := make(chan []int)
    

    5.5 在浏览器中查看

    (pprof) web
    

    5.6 base基准分析

    除了上面的分析方法,pprof还提供了更强大的工具用于对比前后特征文件的不同。下例使用了-base标志,后跟基准特征文件。

    # 使用基准值
    ➜  go tool pprof -base pprof.app.goroutine.001.pb.gz pprof.app.goroutine.002.pb.gz
    File: app
    Type: goroutine
    Time: Nov 16, 2021 at 10:12pm (CST)
    Entering interactive mode (type "help" for commands, "o" for options)
    (pprof) top
    Showing nodes accounting for 28, 100% of 28 total
          flat  flat%   sum%        cum   cum%
            28   100%   100%         28   100%  runtime.gopark
             0     0%   100%         28   100%  52lu/go-pprof/scenes.errorUse.func1
             0     0%   100%         28   100%  time.Sleep
    (pprof)➜  pprof go tool pprof -base pprof.app.goroutine.001.pb.gz pprof.app.goroutine.002.pb.gz
    File: app
    Type: goroutine
    Time: Nov 16, 2021 at 10:12pm (CST)
    Entering interactive mode (type "help" for commands, "o" for options)
    (pprof) top
    Showing nodes accounting for 28, 100% of 28 total
          flat  flat%   sum%        cum   cum%
            28   100%   100%         28   100%  runtime.gopark
             0     0%   100%         28   100%  52lu/go-pprof/scenes.errorUse.func1
             0     0%   100%         28   100%  time.Sleep
    

    从上面可以看出,后一个基准特征文件比前一个基准特征文件多了28个协程,其中28个协程都处于执行runtime.gopark阶段,从而可以判断协程是否已经泄漏。

    6. 排查锁竞争情况

    mutex主要用于查看锁争用导致的休眠时间,这有助于排查由于锁争用导致CPU利用率不足的问题,需要注意的是:默认不开启锁的竞争分析,需要调用runtime.SetMutexProfileFraction进行设置。开启方式如下:

    func init() {
        // 开启http端口,用协程的方式监听,否则会阻塞
        go func() {
            if err := http.ListenAndServe(":6060", nil); err != nil {
                fmt.Println("pprof err:",err)
            }
        }()
      // 开启锁争用分析
        // 默认不开启锁的竞争分析,需要调用runtime.SetMutexProfileFraction进行设置。
        runtime.SetMutexProfileFraction(1)
    }
    

    6.1 进入交互式

    ➜ go tool pprof http://127.0.0.1:6060/debug/pprof/mutex
    Fetching profile over HTTP from http://127.0.0.1:6060/debug/pprof/mutex
    Saved profile in /Users/liuqh/pprof/pprof.contentions.delay.007.pb.gz
    Type: delay
    Time: Nov 17, 2021 at 3:04pm (CST)
    Entering interactive mode (type "help" for commands, "o" for options)
    

    6.2 排序互斥耗时

    (pprof) top
    Showing nodes accounting for 37.09s, 100% of 37.09s total
          flat  flat%   sum%        cum   cum%
        37.09s   100%   100%     37.09s   100%  sync.(*Mutex).Unlock
             0     0%   100%     37.09s   100%  52lu/go-pprof/scenes.UseMutexDemo.func1
    

    由上面可以看出,锁争用集中在互斥锁中,互斥带来的休眠时间为37.09s

    6.3 查看具体代码

    # 查看具体函数
    (pprof) list UseMutexDemo
    Total: 37.09s
    ROUTINE ======================== 52lu/go-pprof/scenes.UseMutexDemo.func1 in /Users/liuqh/ProjectItem/GoItem/go-pprof/scenes/mutex.go
             0     37.09s (flat, cum)   100% of Total
             .          .     21:            stu.idList = append(stu.idList, id)
             .          .     22:            time.Sleep(time.Millisecond * 200)
             .          .     23:        }()
             .          .     24:    }
             .          .     25:}
    

    6.4 在浏览器中查看

    (pprof) web
    
    image.png

    7. 排查阻塞操作

    在程序中,除了锁的争用会导致阻塞之外,很多逻辑都会导致阻塞,比如网络请求超时、IO阻塞等。需要注意的是:默认不开启阻塞分析,需要调用runtime.SetMutexProfileFraction进行设置。开启方式如下:

    func init() {
        ...
        // 开启block分析
        runtime.SetBlockProfileRate(1)
    }
    

    7.1 查看/debug/pprof

    1. 当前阻塞数量

    image.png

    2. 具体阻塞位置

    image.png

    7.2 进入交互式

    ➜ go tool pprof http://127.0.0.1:6060/debug/pprof/block
    Fetching profile over HTTP from http://127.0.0.1:6060/debug/pprof/block
    Saved profile in /Users/liuqh/pprof/pprof.contentions.delay.012.pb.gz
    Type: delay
    Time: Nov 17, 2021 at 4:30pm (CST)
    Entering interactive mode (type "help" for commands, "o" for options)
    

    7.3 排序阻塞时间

    (pprof) top
    Showing nodes accounting for 59.75s, 100% of 59.75s total
    Dropped 4 nodes (cum <= 0.30s)
          flat  flat%   sum%        cum   cum%
        59.75s   100%   100%     59.75s   100%  runtime.chanrecv1
             0     0%   100%     59.75s   100%  52lu/go-pprof/scenes.UseBlockDemo (inline)
             0     0%   100%     59.75s   100%  52lu/go-pprof/scenes.handle
             0     0%   100%     59.75s   100%  main.main
             0     0%   100%     59.75s   100%  runtime.main
    
    • runtime.chanrecv1: 代表通道chan读取时,阻塞。

    7.4 查看具体阻塞代码

    # 查看UseBlockDemo函数,发现内部调用函数handle,且handle函数耗时59.75s
    (pprof) list Use
    Total: 59.75s
    ROUTINE ======================== 52lu/go-pprof/scenes.UseBlockDemo in /Users/liuqh/ProjectItem/GoItem/go-pprof/scenes/block.go
             0     59.75s (flat, cum)   100% of Total
             .          .      6:var sqlCh = make(chan []string)
             .          .      7:var bCh = make(chan bool)
             .          .      8:
             .          .      9:func UseBlockDemo() {
             .          .     10:    for i := 0; i < 1000; i++ {
             .     59.75s     11:        handle()
             .          .     12:    }
             .          .     13:}
             .          .     14:
             .          .     15:func handle()  {
             .          .     16:    // 等待文件写入
    # 查看handle
    (pprof) list handle
    Total: 59.75s
    ROUTINE ======================== 52lu/go-pprof/scenes.handle in /Users/liuqh/ProjectItem/GoItem/go-pprof/scenes/block.go
             0     59.75s (flat, cum)   100% of Total
             .          .     16:    // 等待文件写入
             .          .     17:    go func() {
             .          .     18:        time.Sleep(time.Second)
             .          .     19:        bCh <- true
             .          .     20:    }()
             .     35.08s     21:    <-bCh
             .          .     22:    // 发起网络请求
             .          .     23:    go func() {
             .          .     24:        time.Sleep(time.Millisecond * 500)
             .          .     25:        reqCh <- "req success"
             .          .     26:    }()
             .          .     27:    // 阻塞等待
             .     17.59s     28:    <-reqCh
             .          .     29:    // 执行SQL查询
             .          .     30:    go func() {
             .          .     31:        time.Sleep(time.Millisecond * 200)
             .          .     32:        sqlCh <- []string{"hello","world"}
             .          .     33:    }()
             .      7.08s     34:    <-sqlCh
             .          .     35:}
             .          .     36:
    

    7.5 在浏览器中查看

    相关文章

      网友评论

          本文标题:go包:pprof调试器的使用

          本文链接:https://www.haomeiwen.com/subject/azlcddtx.html