作为一个golang coder,使用golang编写代码是基本的要求。

能够写出代码,并能够熟悉程序执行过程中各方面的性能指标,则是更上一层楼。

如果在程序出现性能问题的时候,可以快速定位和解决问题,那么写起代码来,会更加自信。

本文介绍的pprof,是golang 自带性能剖析工具,可以帮助定位程序中可能存在的问题。

1.profile文件的收集

pprof使用profile文件进行性能分析,profile文件是应用程序执行状态的数据。

收集profile文件有两种方式,对应go 语言提供的 runtime/pprof 和 net/http/pprof 两个库。

1.1 runtime/pprof

一般用于应用程序执行一段时间后,就会结束的情况。

例如,进行CPU profiling:

f, err := os.Create(*cpuprofile)
...
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()

应用程序启动时开始收集,应用程序结束后,就生成一个文件。

再例如,进行Mem profiling:

f, err := os.Create(*memprofile)
pprof.WriteHeapProfile(f)
f.Close()

生成一个mem profile文件。

1.2 net/http/pprof

这种方式主要用于程序一直在跑的场景。

如果使用了默认的 http.DefaultServeMux(通常是代码直接使用 http.ListenAndServe("0.0.0.0:8000", nil)),只需要添加一行:

import _ "net/http/pprof"

如果你使用自定义的 Mux,则需要手动注册一些路由规则:

r.HandleFunc("/debug/pprof/", pprof.Index)
r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
r.HandleFunc("/debug/pprof/profile", pprof.Profile)
r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
r.HandleFunc("/debug/pprof/trace", pprof.Trace)

不管哪种方式,你的 HTTP 服务都会多出 /debug/pprof endpoint,访问它会得到类似下面的内容:

/debug/pprof/

profiles:
0 block
62 goroutine
444 heap
30 threadcreate full goroutine stack dump

下面的演示中,使用的例子代码如下:

/*simple.go*/

package main

import (
"log"
_ "net/http/pprof"
"net/http"
"time"
) func main() { go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}() go worker() select{}
} // simple worker
func worker(){ strSlice := []string{}
for {
str := "hello world "
strSlice = append(strSlice, str) time.Sleep(time.Second)
} }

代码开始引入net/http/pprof,在端口6060启动http服务。

启动应用程序

go build simple.go

./simpe

2.pprof分析profiling数据

pprof分析profiling数据主要有两种方式:

  • 交互式终端
  • 页面显示

2.1 交互式终端

2.1.1 查看内存使用情况

使用heap profile查看内存使用情况。

go tool pprof http://localhost:6060/debug/pprof/heap
Fetching profile over HTTP from http://localhost:6060/debug/pprof/heap
Saved profile in /Users/lanyang/pprof/pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
Type: inuse_space
Time: Sep 21, 2019 at 1:56pm (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)
(pprof) top10
Showing nodes accounting for 514kB, 100% of 514kB total
flat flat% sum% cum cum%
514kB 100% 100% 514kB 100% unicode.init
0 0% 100% 514kB 100% runtime.doInit
0 0% 100% 514kB 100% runtime.main
(pprof)

默认的Type是inuse_space,即常驻内存.

与之对应的是alloc_objects,表示临时分配的内存。

列出top10的内存占用。

2.1.2 查看CPU使用情况

使用cpu profile查看cpu使用情况。

例如查看过去30s的cpu profile

go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
Fetching profile over HTTP from http://localhost:6060/debug/pprof/profile?seconds=30
Saved profile in /Users/lanyang/pprof/pprof.samples.cpu.001.pb.gz
Type: cpu
Time: Sep 21, 2019 at 2:19pm (CST)
Duration: 30s, Total samples = 0
No samples were found with the default sample value type.
Try "sample_index" command to analyze different sample values.
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

2.1.3 保存profile文件

从pprof使用上看,是首先保存profile文件,再进行分析的。

在一些场景,例如在线上环境,最好先保存profile,然后拿到线下做分析。

将profile文件保存下来:

wget  http://localhost:6060/debug/pprof/heap
--2019-09-21 15:20:17-- http://localhost:6060/debug/pprof/heap
正在解析主机 localhost (localhost)... ::1, 127.0.0.1
正在连接 localhost (localhost)|::1|:6060... 失败:Connection refused。
正在连接 localhost (localhost)|127.0.0.1|:6060... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:1162 (1.1K) [application/octet-stream]
正在保存至: “heap” heap 100%[============================================================================================>] 1.13K --.-KB/s 用时 0s 2019-09-21 15:20:17 (111 MB/s) - 已保存 “heap” [1162/1162]) ll
-rw-r--r-- 1 lanyang staff 1.1K 9 21 15:20 heap

然后使用pprof进行分析,其中,./simple是可执行文件,用于解析各种符号,./heap是刚才获取到的profile文件。

go tool pprof ./simple ./heap
Type: inuse_space
Time: Sep 21, 2019 at 3:20pm (CST)
No samples were found with the default sample value type.
Try "sample_index" command to analyze different sample values.
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

2.2 页面显示

2.2.1 浏览器打开pprof页面

浏览器中打开http://localhost:6060/debug/pprof/

如图所示,列出了很多监控项,

 Profile Descriptions:

allocs:
A sampling of all past memory allocations block:
Stack traces that led to blocking on synchronization primitives cmdline:
The command line invocation of the current program goroutine:
Stack traces of all current goroutines heap:
A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample. mutex:
Stack traces of holders of contended mutexes profile:
CPU profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool pprof command to investigate the profile. threadcreate:
Stack traces that led to the creation of new OS threads trace:
A trace of execution of the current program. You can specify the duration in the seconds GET parameter. After you get the trace file, use the go tool trace command to investigate the trace.

可以通过链接跳转到对应界面。

2.2.2. 更详细的页面显示

go 从1.11开始的pprof提供了更丰富性能数据展示方式,包括火焰图,直接使用如下命令:

$ go tool pprof -http=":8081" [binary] [profile]

会打开浏览器页面。

端口可以自己选择,这里使用了8081。

binary是应用程序的可执行文件,读取符号信息。

profile 是profile文件,可以是本地文件,或者http地址。

例如,使用本地保存的profile文件:

$ go tool pprof -http=":8081" ./simple ./heap

或者,通过http 的profile:

go tool pprof -http=":8081" ./simple  http://localhost:6060/debug/pprof/heap
Fetching profile over HTTP from http://localhost:6060/debug/pprof/heap
Saved profile in /Users/zhangyunyang/pprof/pprof.simple.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
Serving web UI on http://localhost:8081

火焰图如图所示,示例代码比较简单,所以火焰图不是很明显。

如果不能使用go1.11,则可以使用最新的pprof工具:

# Get the pprof tool directly
$ go get -u github.com/google/pprof $ pprof -http=":8081" [binary] [profile]

3.参考

Package pprof

使用 pprof 和火焰图调试 golang 应用

Profiling Go Programs

go-torch

最新文章

  1. MS SQL Could not obtain information about Windows NT group/user 'domain\login', error code 0x5. [SQLSTATE 42000] (Error 15404)
  2. no module named flask.ext.login
  3. Oracle存储过程执行update语句不报错不生效问题
  4. C/C++ 获取汉字拼音首字母
  5. Nginx + Tomcat 动静分离实现负载均衡(转)
  6. STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷
  7. spring交易声明的几个传播特性
  8. Spring 学习笔记(七)—— 切入点表达式
  9. 读书笔记-你不知道的JS上-this
  10. C Primer Plus Study Note
  11. 如何在 Koa 中获取 client 的 ip 以及 port
  12. vmware-vcsa6.5 基本管理
  13. Python中read()、readline()和readlines()三者间的区别和用法
  14. c# 线程的生命周期
  15. 阅读OReilly.Web.Scraping.with.Python.2015.6笔记---BeautifulSoup---findAll
  16. BZOJ 2561 最小生成树 | 网络流 最小割
  17. 主调度器schedule
  18. listview的两种适配器
  19. API文档管理平台
  20. [转] Windows局域网通过NTP设置时间同步

热门文章

  1. 20、linux启动流程和救援模式
  2. 【转】Qt 资源图片删除后,错误 needed by `debug/qrc_image.cpp'. Stop. 的终极解决办法
  3. 一、传统MVC token验证方式
  4. django_celery_results安装的坑
  5. K-MEANS算法及sklearn实现
  6. 牛客小白月赛12 C 华华给月月出题 (积性函数,线性筛)
  7. dedecms织梦后台发布文章提示“标题不能为空”的解决办法
  8. 安装keras和解决python3退格显示^H的问题
  9. 最简单之安装hive
  10. Nginx概念