1. 什么是pprof?为什么需要使用pprof?

1.1 什么是pprof?

  • 用来做性能分析的工具

1.2 pprof可以从哪些角度来进行分析

  • CPU Profiling:CPU 分析,按照一定的频率采集所监听的应用程序 CPU(含寄存器)的使用情况,可确定应用程序在主动消耗 CPU 周期时花费时间的位置
  • Memory Profiling:内存分析,在应用程序进行堆分配时记录堆栈跟踪,用于监视当前和历史内存使用情况,以及检查内存泄漏
  • Block Profiling:阻塞分析,记录 goroutine 阻塞等待同步(包括定时器通道)的位置
  • Mutex Profiling:互斥锁分析,报告互斥锁的竞争情况

2. pprof 怎么使用?

package main

import (
    "encoding/json"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "net/http"
    netpprof "net/http/pprof"
    "os"
    "runtime/pprof"
    "time"
)

func main() {
    //pprofSingerProgram() // 分析单个程序示例
    //pprofHttp()          // 分析http服务示例
    pprofDiyHttp() // 分析自定义http服务示例
}

func pprofSingerProgram() {
    f, _ := os.Create("./test.pprof")
    pprof.StartCPUProfile(f)
    defer pprof.StopCPUProfile()
    for i := 0; i < 100000; i++ {
        LocalTz()
        DoSomething([]byte(`{"a": 1, "b": 2, "c": 3}`))
    }
}

func pprofHttp() {
    go func() {
        for {
            LocalTz()
            DoSomething([]byte(`{"a": 1, "b": 2, "c": 3}`))
        }
    }()
    time.Sleep(1)
    fmt.Println("start api server...")
    panic(http.ListenAndServe(":8081", nil))
}

func pprofDiyHttp() {
    var httpSvc *http.Server
    httpAddr := ":8081"
    mux := http.NewServeMux()

    mux.HandleFunc("/debug/pprof/", netpprof.Index)
    mux.HandleFunc("/debug/pprof/cmdline", netpprof.Cmdline)
    mux.HandleFunc("/debug/pprof/profile", netpprof.Profile)
    mux.HandleFunc("/debug/pprof/symbol", netpprof.Symbol)
    mux.HandleFunc("/debug/pprof/trace", netpprof.Trace)
    httpSvc = &http.Server{
        Addr:    httpAddr,
        Handler: mux,
    }
    if err := httpSvc.ListenAndServe(); err != nil && err != http.ErrServerClosed {
        fmt.Println(err)
    }
}

func DoSomething(s []byte) {
    var m map[string]interface{}
    err := json.Unmarshal(s, &m)
    if err != nil {
        panic(err)
    }

    s1 := make([]string, 0)
    s2 := ""
    for i := 0; i < 100; i++ {
        s1 = append(s1, string(s))
        s2 += string(s)
    }
}

func LocalTz() *time.Location {
    tz, _ := time.LoadLocation("Asia/Shanghai")
    return tz
}

2.1 在普通的程序中使用

  • 以上代码示例:pprofSingerProgram

2.2 在http server 中使用

  • 以上代码示例:pprofHttp
  • mac 安装 graphviz
  • brew install graphviz
  • 如果遇到报错,可以换成中科大的源,然后执行一下brew update

2.3 在自己定义的http server中 使用

  • 需要自己注册路由

2.3 获取各类数据的地址

  • 获取所有的数据:http://127.0.0.1:6060/debug/pprof/,以下列出其他的相关数据查看,如果你在对应的访问路径上新增 ?debug=1 的话,就可以直接在浏览器访问。否则就是直接下载文件
  • allocs:查看过去所有内存分配的样本,访问路径为 $HOST/debug/pprof/allocs。
  • block:查看导致阻塞同步的堆栈跟踪,访问路径为 $HOST/debug/pprof/block。
  • cmdline: 当前程序的命令行的完整调用路径。
  • goroutine:查看当前所有运行的 goroutines 堆栈跟踪,访问路径为 $HOST/debug/pprof/goroutine。
  • heap:查看活动对象的内存分配情况, 访问路径为 $HOST/debug/pprof/heap。
  • mutex:查看导致互斥锁的竞争持有者的堆栈跟踪,访问路径为 $HOST/debug/pprof/mutex。
  • profile: 默认进行 30s 的 CPU Profiling,得到一个分析用的 profile 文件,访问路径为 $HOST/debug/pprof/profile。
  • threadcreate:查看创建新 OS 线程的堆栈跟踪,访问路径为 $HOST/debug/pprof/threadcreate。

2.4 获取火焰图:

  • go tool pprof -http=:803 http://localhost:802/debug/pprof/profile -seconds 10
  • -http=803: 监听在某个端口以供提供网页端查看
  • -seconds 10 : 收集最近十秒的信息

3. 火焰图怎么看?

  • 如下图,第一个是root,表示所有的函数的起点
  • 一行的数据中的各个函数是平行的,也就是说行元素之间
  • 一列的数据中的各个函数相当于上一行的子函数,向上负责的,也就是说列之间存在父子关系
  • 同时存在一列函数分为多个函数,长度代表他们的耗时



4. 参考链接