程序的日常开发和维护过程中,可能会出现各种各样稀奇古怪的性能问题。所以,一个强大易用的性能分析工具是很有必要的。Golang 标准库就提供了这样一个工具包 pprof (取自Program Profiling 缩写) 。pprof 可以在程序执行过程中收集能够反映程序运行状态的数据并且提供可视化的功能。

工作原理从过程上来说包括两个部分:性能样本数据采集和样本数据分析。

1、性能样本数据采集

在性能样本数据采集过程中,pprof 搜集被分析程序在运行时的一系列的性能概要信息的采样数据,并根据产生的采样数据生成 pprof 可视化工具可以解析的数据格式。

2、性能样本数据分析

pprof 工具本身提供了命令行工具,可以对采集到的样本数据进行可视化和性能分析。

对于 Golang 程序来说,主要关注下几方面的性能指标:

  • CPU 使用情况

  • 内存使用情况

  • 导致阻塞(Block)的同步原语情况

  • goroutine 的使用情况

短生命程序是指执行完任务后就退出的程序,例如一次性任务、定时任务和离线处理任务。这类程序可以使用 runtime/pprof 库来做性能分析。这个库会将样本数据写入文件中,示例代码如下:

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"runtime/pprof"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")

funcmain() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		defer f.Close() // error handling omitted for example
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
		defer pprof.StopCPUProfile()
		fmt.Println("hhhhh")
	}

	// ... rest of the program ...

}

开始进行 CPU Profiling 调用 pprof.StartCPUProfile() 方法即可,停止分析调用调用 StopCPUProfile() 方法即可。执行完成后,会生成 cpuprofile 文件,里面包含了 cpu 样本数据。

服务类程序是指是一直运行的程序,比如 http 服务和 rpc 服务,这类程序可以使用 net/http/pprof 库来做性能分析。这个库会提供一个标准的 http 接口来用于做性能分析。最简单的做法是在代码里添加如下一行

import _ "net/http/pprof"

示例代码如下

package main

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

funcIndexHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "hello world")
}

funcmain() {
	http.HandleFunc("/test", IndexHandler)
	http.ListenAndServe(":8000", nil)
}

在浏览器中先访问

http://127.0.0.1:8000/test ,然后访问 http://127.0.0.1:8000/debug/pprof/ 即可看到样本数据.

  • net/http/pprof 提供的几个重点接口:

  • /debug/pprof/:样本数据首页,以下几个接口都可以通过点击首页的各列表项进入

  • /debug/pprof/heap:访问这个接口会得到内存 Profiling 结果的文件

  • /debug/pprof/block:访问这个接口会得到 block Profiling 结果的文件

  • /debug/pprof/goroutine:goroutines 列表及调用关系

本文主要介绍了 Go 语言性能分析工具 pprof 的原理和程序中如何引入 pprof,下篇文章会介绍如何使用 pprof 来分析样本数据。