前言

使用pprof和Graphviz结合来分析golang程序的性能问题。

1、pprof

golang官方用来做监控分析的库,一般都是pprof,我们这里使用的net/http/pprof可以做到直接看到当前web服务的状态,包括cpu,内存等的使用情况。

2、Graphviz

Graphviz (英文:Graph Visualization Software的缩写)是一个由AT&T实验室启动的开源工具包,用于绘制DOT语言脚本描述的图形。它也提供了供其它软件使用的函式库。什么是Graphviz

一、pprof的使用1、Graphviz安装

下载graphviz,zip和mis看个人情况,都可以,这边使用的是2.38 Stable Release的zip,解压后直接使用。

解压或者安装后设置环境变量:

golang ebpf 监控网络_pprof

2、pprof的介绍

官方提供了一个名为net/http/pprof的包,用于go程序的性能检测。在这个包中已经实现了已经uri,加载这个包然后监听一个端口就可以在程序运行的过程中获取到实时的一些信息。官方部分描述文件:

golang ebpf 监控网络_golang_02

我们可以使用2种方式来查看pprof提供的性能检测数据:

在监听的端口上使用命令获取

自定义url调用pprof提供的指令将性能数据写到指定文件中查看 下面我们就这两种方式分别说明:

2.1 使用命令查看

官方的文档中提供了使用命令查看的详细过程。

2.1.1 如何使用

在应用程序中引入net/http/pprof包,并且监听一个http端口即可。

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

func main() {
	addr := "localhost:6060"
	go func() {
		if err := http.ListenAndServe(addr,nil); err != nil {
			panic(err)
		}
	}()
	// TODO 
	select{}
}

上面代码表示在端口6060上监听了pprof的性能url,通过既定的一些命令可以查看不通的性能数据。

2.1.2 性能数据的命令

  在终端或者浏览器上可以使用命令查看heap profile、cpu profile、block profile、mutex profile和trace 信息,部分命令可以增加采集的时间,采集到不同时长的数据。

  启动已经增加了net/http/pprof包的程序,在另一个打开的终端上输入上面的指令,会返回一个pprof的命令行,在这个命令行中通过一个指令就可以查看细节。

  • heap profilego tool pprof http://localhost:6060/debug/pprof/heap
  • cpu profilego tool pprof http://localhost:6060/debug/pprof/profile?seconds=30 这句话表示采集时常为30s的cpu信息
  • block profilego tool pprof http://localhost:6060/debug/pprof/block
  • mutex profilego tool pprof http://localhost:6060/debug/pprof/mutex
  • tracewget http://localhost:3030/debug/pprof/trace?seconds=5trace数据有一些不一样。net/http/pprof包给trace信息返回的是一个文件,上面命令表示获取5s钟的trace信息。使用浏览器时,直接输入url就可以采集到对应时常的trace信息。 trace文件存下来后,需要用到go tool 的trace命令来解析,才能像其他的命令一样看到详细的tracec信息。 执行go tool trace trace文件解析trace文件,之后会有一个端口,在这个端口上查看trace信息。如下如:
  • golang ebpf 监控网络_Graphviz_03

2.1.3 查看

我们以cpu profile命令为例说明。启动demo程序后,在另一个终端中输入go tool pprof http://localhost:3030/debug/pprof/profile?seconds=10后,等待10s钟后,过程如下:

1)采集数据

golang ebpf 监控网络_golang_04

2)采集完成后

采集完成后可以使用命令查看,详细的命令可以输入help查看。我们这里以web命令使用Graphviz查看图形关系。

golang ebpf 监控网络_golang_05

3)web产生的图形关系

通过分析web中的图像关系就可以比较详细的看出cpu的使用情况。

golang ebpf 监控网络_golang ebpf 监控网络_06

2.2 文件存储查看

  直接查看的指令会能够完全提供查看性能数据的需求,但是有一些场景我们需要把一些文件拿下来慢慢分析,这时候将采集到的信息写入文件是必须的。鉴于此,基于go原生的net/http对net/http/pprof进行了封装,并提供接口便于控制。

2.2.1 一个基于原生包的接口封装

这个封装提供两个接口:初始化pprof包的函数和安全关闭pprof的http函数。对外使用/start开始采集数据,默认打开关闭gc;/startnogc开始采集数据并且关闭了gc;/stop停止采集数据。

1)初始化函数Pprof

func Pprof(port int) {
	addrs := fmt.Sprintf("localhost:%d", port)
	log.Printf("pprof listen addr=[%v]", addrs)

	http.HandleFunc("/start", handleStart)
	http.HandleFunc("/stop", handleStop)

	srv = &http.Server{
		Addr:    addrs,
		Handler: nil,
	}
	go func(addr string) {
		if err := srv.ListenAndServe(); err != nil {
			log.Panic(err)
		}
	}(addrs)
}

2)关闭http-srv句柄函数Shutdown

func Shutdown() error {
	ctx, cancle := context.WithTimeout(context.Background(), time.Duration(1))
	defer cancle()
	if err := srv.Shutdown(ctx); err != nil {
		log.Printf("stop srv failed,%v", err)
		return err
	}
	return nil
}
2.2.2 如何使用

使用时先初始化,当程序退出时需要调用Shutdown释放资源。

func main() {
	logger = log.New(os.Stdout, "", log.Lshortfile|log.Ldate|log.Ltime)
	pprof.Pprof(3030)
	logger.Printf("++++++++")
	result1 := gen(1, 100000000)
	result2 := gen(2, 20000000)
	for range merge(result1, result2) {
		_count++
	}
	HandlerExit(func(s os.Signal) int {
		logger.Printf("receive get a signal %s", s.String())
		if err := pprof.Shutdown(); err != nil {
			logger.Printf(" service exit, error: %s", err)
			return 1
		}
		logger.Printf(" service exit")
		return 0
	})
}
2.2.3 产生的文件和查看

1)产生的文件

发送/start或/startgc后,会在可执行文件的目录下产生一个名为pprof的目录,存在4个文件。

golang ebpf 监控网络_性能分析_07

2)查看block、mem和cpu   对于block.pprof、cpu.pprof和mem.pprof文件,查看的指令是一样的。在当前的目录下打开终端,输入go tool pprof 文件名即可。以cpu为例说明:

(1)使用命令解析cpu.pprof文件

golang ebpf 监控网络_性能分析_08

(2)输入指令查看细节

  这里还是以web命令示范,直接在浏览器查看性关系图

golang ebpf 监控网络_性能分析_09

3)查看trace的方式在在线查看的部分说过,此处不再赘述

trace.out的数据内容较多,我们在 golang学习笔记-pprof性能分析2 单独分析