一、golang 程序性能调优

在 golang 程序中,有哪些内容需要调试优化?

一般常规内容:

  1. cpu:程序对cpu的使用情况 - 使用时长,占比等
  2. 内存:程序对cpu的使用情况 - 使用时长,占比,内存泄露等。如果在往里分,程序堆、栈使用情况
  3. I/O:IO的使用情况 - 哪个程序IO占用时间比较长

golang 程序中:

  1. goroutine:go的协程使用情况,调用链的情况
  2. goroutine leak:goroutine泄露检查
  3. go dead lock:死锁的检测分析
  4. data race detector:数据竞争分析,其实也与死锁分析有关

上面是在 golang 程序中,性能调优的一些内容。

有什么方法工具调试优化 golang 程序?

比如 linux 中 cpu 性能调试,工具有 top,dstat,perf 等。

那么在 golang 中,有哪些分析方法?

golang 性能调试优化方法:

  • Benchmark基准测试,对特定代码的运行时间和内存信息等进行测试
  • Profiling程序分析,程序的运行画像,在程序执行期间,通过采样收集的数据对程序进行分析
  • Trace跟踪,在程序执行期间,通过采集发生的事件数据对程序进行分析

profiling 和 trace 有啥区别?

profiling 分析没有时间线,trace 分析有时间线。

在 golang 中,应用方法的工具呢?

这里介绍 pprof 这个 golang 工具,它可以帮助我们调试优化程序。

它的最原始程序是 gperftools - https://github.com/gperftools/gperftools,golang 的 pprof 是从它而来的。

二、pprof 介绍

简介

pprof 是 golang 官方提供的性能调优分析工具,可以对程序进行性能分析,并可视化数据,看起来相当的直观。

当你的 go 程序遇到性能瓶颈时,可以使用这个工具来进行调试并优化程序。

本文将对下面 golang 中 2 个监控性能的包 pprof 进行运用:

  • runtime/pprof:采集程序运行数据进行性能分析,一般用于后台工具型应用。
  • net/http/pprof:对 runtime/pprof 的二次封装,一般应用于 http server ,采集 http server 运行时数据进行分析。

pprof 开启后,每隔一段时间就会采集当前程序的堆栈信息,获取函数的 cpu、内存等使用情况。通过对采样的数据进行分析,形成一个数据分析报告。

pprof 以 profile.proto 的格式保存数据,然后根据这个数据生成可视化的分析报告,支持文本形式和图形形式报告。

profile.proto 里具体的数据格式是 protocol buffers

pprof 使用模式

  • Report generation:报告生成

  • Interactive terminal use:交互式终端

  • Web interface:Web 界面

三、runtime/pprof

前提条件

先安装 pprof: go get -u github.com/google/pprof

调试分析 golang 程序,要开启 profile 然后开始采样数据。

采样数据的方式:

  • 第 1 种,在 go 程序中添加如下代码:

    StartCPUProfile 为当前 process 开启 CPU profiling 。

    StopCPUProfile 停止当前的 CPU profile。当所有的 profile 写完了后它才返回。
// 开启 cpu 采集分析:
pprof.StartCPUProfile(w io.Writer) // 停止 cpu 采集分析:
pprof.StopCPUProfile()

WriteHeapProfile 把内存 heap 相关的内容写入到文件中

pprof.WriteHeapProfile(w io.Writer)
  • 第 2 种,在 benchmark 测试的时候
go test -cpuprofile cpu.prof -memprofile mem.prof -bench .
  • 还有一种,对 http server 采集数据
go tool pprof $host/debug/pprof/profile

程序示例

go version go1.13.9

例子 1

我们用第 1 种方法,在程序中添加分析代码,demo.go :

package main

import (
"bytes"
"flag"
"log"
"math/rand"
"os"
"runtime"
"runtime/pprof"
"sync"
) var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
var memprofile = flag.String("memprofile", "", "write mem profile to `file`") func main() {
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal("could not create CPU profile: ", err)
}
defer f.Close() if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal("could not start CPU profile: ", err)
}
defer pprof.StopCPUProfile()
} var wg sync.WaitGroup
wg.Add(200) for i := 0; i < 200; i++ {
go cyclenum(30000, &wg)
} writeBytes() wg.Wait() if *memprofile != "" {
f, err := os.Create(*memprofile)
if err != nil {
log.Fatal("could not create memory profile: ", err)
}
defer f.Close()
runtime.GC() if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal("cound not write memory profile: ", err)
}
}
} func cyclenum(num int, wg *sync.WaitGroup) {
slice := make([]int, 0)
for i := 0; i < num; i++ {
for j := 0; j < num; j++ {
j = i + j
slice = append(slice, j)
}
}
wg.Done()
} func writeBytes() *bytes.Buffer {
var buff bytes.Buffer for i := 0; i < 30000; i++ {
buff.Write([]byte{'0' + byte(rand.Intn(10))})
}
return &buff
}

编译程序、采集数据、分析程序:

  1. 编译 demo.go
go build demo.go
  1. 用 pprof 采集数据,命令如下:
./demo.exe --cpuprofile=democpu.pprof  --memprofile=demomem.pprof

说明:我是 win 系统,这个 demo 就是 demo.exe ,linux 下是 demo

  1. 分析数据,命令如下:
go tool pprof democpu.pprof

go tool pprof 简单的使用格式为:go tool pprof [binary] [source]

  • binary: 是应用的二进制文件,用来解析各种符号
  • source: 表示 profile 数据的来源,可以是本地的文件,也可以是 http 地址

要了解 go tool pprof 更多命令使用方法,请查看文档:go tool pprof --help

注意

获取的 Profiling 数据是动态的,要想获得有效的数据,请保证应用处于较大的负载(比如正在生成中运行的服务,或者通过其他工具模拟访问压力)。否则如果应用处于空闲状态,得到的结果可能没有任何意义。

(后面会遇到这种问题)

分析数据,基本的模式有 2 种:

  • 一个是命令行交互分析模式
  • 一个是图形可视化分析模式

命令行交互分析

  1. 分析上面采集的数据,命令: go tool pprof democpu.pprof

字段 说明
Type 分析类型,这里是 cpu
Duration 程序执行的时长

Duration 下面还有一行提示,这是交互模式(通过输入 help 获取帮助信息,输入 o 获取选项信息)。

可以看出,go 的 pprof 操作还有很多其他命令。

  1. 输入 help 命令,出来很多帮助信息:

Commands 下有很多命令信息,text ,top 2个命令解释相同,输入这个 2 个看看:

  1. 输入 top,text 命令

top 命令:对函数的 cpu 耗时和百分比排序后输出

top后面还可以带参数,比如: top 15

输出了相同的信息。

字段 说明
flat 当前函数占用 cpu 耗时
flat % 当前函数占用 cpu 耗时百分比
sum% 函数占用 cpu 时间累积占比,从小到大一直累积到 100%
cum 当前函数加上调用当前函数的函数占用 cpu 的总耗时
%cum 当前函数加上调用当前函数的函数占用 cpu 的总耗时占比

从字段数据我们可以看出哪一个函数比较耗费时间,就可以对这个函数进一步分析。

分析用到的命令是 list

list 命令:可以列出函数最耗时的代码部分,格式:list 函数名

从上面采样数据可以分析出总耗时最长的函数是 main.cycylenum,用 list cyclenum 命令进行分析,如下图:

发现最耗时的代码是 62 行:slice = append(slice, j) ,这里耗时有 1.47s ,可以对这个地方进行优化。

这里耗时的原因,应该是 slice 的实时扩容引起的。那我们空间换时间,固定 slice 的容量,make([]int, num * num)

可视化分析

A. pprof 图形可视化

除了上面的命令行交互分析,还可以用图形化来分析程序性能。

图形化分析前,先要安装 graphviz 软件,

下载对应的平台安装包,安装完成后,把执行文件 bin 放入 Path 环境变量中,然后在终端输入 dot -version 命令查看是否安装成功。

生成可视化文件:

有 2 个步骤,根据上面采集的数据文件 democpu.pprof 来进行可视化:

  1. 命令行输入:go tool pprof democpu.pprof
  2. 输入 web 命令

在命令行里输入 web 命令,就可以生成一个 svg 格式的文件,用浏览器打开即可查看 svg 文件。

执行上面 2 个命令如下图:

用浏览器查看生成的 svg 图:

(文件太大,只截取了一小部分图,完整的图请自行生成查看)

关于图形的一点说明:

  1. 每个框代表一个函数,理论上框越大表示占用的 cpu 资源越多
  2. 每个框之间的线条代表函数之间的调用关系,线条上的数字表示函数调用的次数
  3. 每个框中第一行数字表示当前函数占用 cpu 的百分比,第二行数字表示当前函数累计占用 cpu 的百分比
B. 火焰图 Flame Graph

火焰图 (Flame Graph) 是性能优化专家 Bredan Gregg 创建的一种性能分析图。Flame Graphs visualize profiled code。

火焰图形状如下:

(来自:https://github.com/brendangregg/FlameGraph)

上面用 pprof 生成的采样数据,要把它转换成火焰图,就要使用一个转换工具 go-torch,这个工具是 uber 开源,它是用 go 语言编写的,可以直接读取 pprof 采集的数据,并生成一张火焰图, svg 格式的文件。

  1. 安装 go-torch:

go get -v github.com/uber/go-torch

  1. 安装 flame graph:

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

  1. 安装 perl 环境:

生成火焰图的程序 FlameGraph 是用 perl 写的,所以先要安装执行 perl 语言的环境。

  • 安装 perl 环境:https://www.perl.org/get.html
  • 把执行文件 bin 加入 Path 中
  • 在终端下执行命令:perl -h ,输出了帮助信息,则说明安装成功

  1. 验证 FlameGraph 是否安装成功:

进入到 FlameGraph 安装目录,执行命令,./flamegraph.pl --help

输出信息说明安装成功

  1. 生成火焰图:

重新进入到文件 democpu.pprof 的目录,然后执行命令:

go-torch -b democpu.pprof

上面命令默认生成名为 torch.svg 的文件,用浏览器打开查看:

自定义输出文件名,后面加 -f 参数:

go-torch -b democpu.pprof -f cpu_flamegraph.svg

火焰图说明:

火焰图 svg 文件,你可以点击上面的每个方块来查看分析它上面的内容。

火焰图的调用顺序从下到上,每个方块代表一个函数,它上面一层表示这个函数会调用哪些函数,方块的大小代表了占用 CPU 使用时长长短。

go-torch 的命令格式:

go-torch [options] [binary] <profile source>

go-torch 帮助文档:

想了解更多 go-torch 用法,请用 help 命令查看帮助文档,go-torch --help

或查看 go-torch README 文档 。

四、参考

golang 性能调优分析工具 pprof (上)的更多相关文章

  1. golang 性能调优分析工具 pprof(下)

    golang 性能调优分析工具 pprof(上)篇, 这是下篇. 四.net/http/pprof 4.1 代码例子 1 go version go1.13.9 把上面的程序例子稍微改动下,命名为 d ...

  2. Golang性能调优入门

    如何利用golang自带的profile工具进行应用程序的性能调优,前一段时间我做的日志分析系统在线上遇到了一个问题,就是分任务的系统down机了,日志处理延迟了10几个小时,这个时候任务分发系统重启 ...

  3. Kafka性能调优分析-线上环境篇

    一.背景介绍: 在平时的开发中,使用kafka来发送数据已经非常熟悉,但是在使用的过程中,其实并没有比较深入的探索kafka使用过程中 一些参数配置,带来的损失可能就是没有充分的发挥出kfka的优势, ...

  4. 专题:性能调优之工具---perf

    1. Linux Perf简介 1.1 Perf是什么 Perf 是内置于Linux 内核源码树中的性能剖析(profiling)工具.它基于事件采样原理,以性能事件为基础,支持针对处理器相关性能指标 ...

  5. Java性能调优—— VisualVM工具基本使用及监控本地和远程JVM进程超详细使用教程

  6. .NET性能调优之一:ANTS Performance Profiler的使用

    .NET性能调优系列文章 系列文章索引 .NET性能调优之一:ANTS Performance Profiler的使用 .NET性能调优之二:使用Visual Studio进行代码度量 .NET性能调 ...

  7. 【Java/Android性能优3】Android性能调优工具TraceView使用介绍

    本文转自:http://blog.csdn.net/innost/article/details/9008691 在软件开发过程中,想必很多读者都遇到过系统性能问题.而解决系统性能问题的几个主要步骤是 ...

  8. 【Java/Android性能优2】Android性能调优工具TraceView介绍

    本文参考:http://www.trinea.cn/android/android-traceview/ Android自带的TraceView堪比java的性能调优工具visualvm线程视图,可以 ...

  9. PHP 性能分析第三篇: 性能调优实战

    注意:本文是我们的 PHP 性能分析系列的第三篇,点此阅读 PHP 性能分析第一篇: XHProf & XHGui 介绍 ,或  PHP 性能分析第二篇: 深入研究 XHGui. 在本系列的 ...

随机推荐

  1. 英语能力考试 All In One

    英语能力考试 All In One 托福,雅思,托业 TOEIC 托业考试 Test of English for International Communication (TOEIC) 国际交流英语 ...

  2. React Native for Windows + macOS

    React Native for Windows + macOS React Native 0.63 https://aka.ms/ReactNative https://microsoft.gith ...

  3. how to read the 10th line of a text using shell script

    how to read the 10th line of a text using shell script shell script / bash script question https://l ...

  4. 一个最简单 node.js 命令行工具

    一个最简单 node.js 命令行工具 node.js cli $ node cli.js xyz # OR $ node cli xyz 接受参数 process.argv js "use ...

  5. 根据对象,返回'&键名=值&键名=值‘形式

    Object.prototype.srcCode=function () { var str=''; for(key in this){ if (this.hasOwnProperty(key) == ...

  6. 看超额担保免信任的NGK DeFi 乐高如何打造下一个千倍币?

    2020年中,DeFi的高收益率吸引了大量热钱涌入,DeFi总锁仓量破百亿美金.如今,流动性挖矿的热潮暂时停歇,但对于 NGK DeFi项目来说,它背后的演变进化从未停止. 免信任是 NGK DeFi ...

  7. .Net按模板导出Excel

    最近在项目中遇到需求 需要按照一定的模板导出数据 还是直接上代码 这里贴一部分模板长什么样吧 然后就是代码 大致就是找到模板 复制一份临时文件 然后修改临时文件然后导出数据 代码如下 string a ...

  8. redis5.* 手动构建集群

    1.集群的概念 集群是一组相互独立的.通过高速网络互联的计算机,它们构成了一个组,并以单一系统的模式加以管理.一个客户与集群相互作用时,集群像是一个独立的服务器.集群配置是用于提高可用性和可缩放性.当 ...

  9. node初体验(二)

    1.静态资源访问,需要设置路由和响应标头 2.url模块.path模块.querystring模块 Url { protocol: null, slashes: null, auth: null, h ...

  10. CentOS7集群环境Elastic配置

    CentOS7集群环境Elastic配置 (首先去官网下载elasticsearch的source code并解压到/usr/soft目录下) (以下默认root账户) 1.更改配置文件 文件路径:/ ...