Skip to content

使用 pprof 和火焰图进行性能分析 ​

程序慢在哪,靠猜没用。Go 的 pprof 采集 CPU、内存、goroutine 等运行数据,火焰图(Flame Graph)把这些数据画成调用栈的图,哪个函数占的时间多一眼能看到。这里记录用这套工具排查死锁和 CPU 消耗热点的过程。

1. pprof 工具简介 ​

pprof 是 Go 内置的性能分析工具,支持 CPU、内存分配、goroutine、阻塞操作等分析,产出的报告用来定位瓶颈。

1.1 安装 pprof ​

pprof 已经在标准库里,go tool pprof 直接能跑。要装可视化工具,用下面的命令:

bash
go install github.com/google/pprof@latest

2. 生成性能分析数据 ​

为了使用 pprof 进行性能分析,我们需要在代码中导入 net/http/pprof 包,并启动一个 HTTP 服务器来暴露性能分析数据。

2.1 示例代码 ​

一个带 pprof 的 HTTP 服务器示例:

go
package main

import (
    "net/http"
    _ "net/http/pprof"
)

func main() {
    // 启动 HTTP 服务器
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, Go!"))
    })

    http.ListenAndServe(":8080", nil)
}

在上述代码中,我们通过 _ "net/http/pprof" 导入 pprof 包,从而在默认的 HTTP 服务器中启用了 pprof 分析功能。

3. 采集和分析性能数据 ​

3.1 采集 CPU 分析数据 ​

在程序运行期间,我们可以使用以下命令采集 CPU 分析数据:

bash
go tool pprof http://localhost:8080/debug/pprof/profile?seconds=30

上述命令将采集 30 秒的 CPU 性能数据,并生成一个可供分析的 pprof 报告文件。

3.2 采集内存分析数据 ​

类似地,我们可以采集内存分析数据:

bash
go tool pprof http://localhost:8080/debug/pprof/heap

3.3 查找死锁 ​

Go 的 pprof 工具还可以帮助我们查找死锁和其他阻塞操作。可以通过以下命令获取当前所有 goroutine 的堆栈信息:

bash
go tool pprof http://localhost:8080/debug/pprof/goroutine

分析 goroutine 的堆栈信息,可以帮助我们识别和定位死锁或其他阻塞问题。

3.4 分析性能数据 ​

我们可以使用 pprof 工具来分析生成的性能数据文件:

bash
go tool pprof [profile_file]

进入 pprof 交互界面后,可以使用以下命令来分析数据:

  • top: 显示 CPU 消耗最大的函数
  • list [function_name]: 查看指定函数的详细信息
  • web: 生成并打开性能数据的可视化图

4. 火焰图 ​

火焰图是一种可视化性能分析结果的工具,通过显示函数调用栈和消耗的时间,帮助我们快速定位性能瓶颈。火焰图的每个矩形代表一个函数,宽度表示该函数的 CPU 时间或内存使用量。

4.1 安装火焰图工具 ​

我们可以使用 Brendan Gregg 提供的 FlameGraph 工具生成火焰图:

bash
git clone https://github.com/brendangregg/FlameGraph.git

4.2 生成火焰图 ​

使用 pprof 生成火焰图所需的折叠文件(folded file):

bash
go tool pprof -raw -output=cpu.pprof http://localhost:8080/debug/pprof/profile?seconds=30

将 pprof 输出转换为火焰图工具可识别的折叠文件格式:

bash
go tool pprof -raw -output=cpu.raw cpu.pprof

使用 FlameGraph 工具生成火焰图:

bash
./FlameGraph/stackcollapse-go.pl cpu.raw > out.folded
./FlameGraph/flamegraph.pl out.folded > cpu_flamegraph.svg

5. 示例:分析和优化代码 ​

5.1 示例代码 ​

以下是一个简单的示例代码,该代码在循环中执行计算:

go
package main

import (
    "net/http"
    _ "net/http/pprof"
    "time"
)

func main() {
    go func() {
        for {
            work()
        }
    }()

    http.ListenAndServe(":8080", nil)
}

func work() {
    time.Sleep(1 * time.Second)
}

5.2 性能分析 ​

运行示例代码并采集 CPU 分析数据:

bash
go tool pprof http://localhost:8080/debug/pprof/profile?seconds=30

分析采集到的性能数据,并生成火焰图:

bash
go tool pprof -raw -output=cpu.pprof http://localhost:8080/debug/pprof/profile?seconds=30
go tool pprof -raw -output=cpu.raw cpu.pprof
./FlameGraph/stackcollapse-go.pl cpu.raw > out.folded
./FlameGraph/flamegraph.pl out.folded > cpu_flamegraph.svg

查看生成的火焰图 cpu_flamegraph.svg,定位程序中的性能瓶颈。

6. 通过 pprof 查找死锁和 CPU 消耗最大的逻辑 ​

在性能分析中,除了常规的 CPU 和内存使用分析,我们还需要关注程序中的死锁和 CPU 消耗最大的逻辑。

6.1 查找死锁 ​

运行以下命令查看当前所有 goroutine 的堆栈信息,帮助识别和定位死锁:

bash
go tool pprof http://localhost:8080/debug/pprof/goroutine

在 pprof 交互界面中,使用 goroutine 命令查看详细的 goroutine 堆栈信息,分析可能的死锁问题。

6.2 查找 CPU 消耗最大的逻辑 ​

在 pprof 交互界面中,使用 top 命令查看 CPU 消耗最大的函数:

bash
go tool pprof [profile_file]
top

使用 list [function_name] 命令查看指定函数的详细信息,帮助定位 CPU 消耗最大的逻辑:

bash
list work

找死锁看 goroutine 堆栈,找热点看 top 和 list,都从 pprof 的交互界面进。

小结 ​

pprof 的工作流是三步:导入 net/http/pprof 暴露端点,go tool pprof 采数据,交互界面里用 top、list、web 看结果。火焰图把同一份数据画成图,矩形宽度就是耗时占比。死锁从 goroutine 堆栈查,CPU 热点从 top 查。

参考资料 ​

相关页面 ​

Hello Golang