Go性能分析工具

前言

作为后端研发,性能分析是我们在研发过程中必然会会遇到的环节,接口耗时、堆栈溢出、内存泄露等等。所谓工欲善其事必先利其器,之前在java中我们是使用arthas这一大神器,不得不说确实好用,想了解arthas的可以看下我之前的文章:Arthas性能分析工具。本节内容我们带来Go的分析神器pprof的使用,帮助我们分析各种性能问题。

pprof介绍

pprof是GoLang程序性能分析工具,和arthas这种工具不一样,pprof是内置在Go里面的,我们只需要开启对应的功能就可以进行采集,本质上还是生成对应的性能数据文件,然后通过pprof打开。不过pprof还提供了web形式的访问,这对于server程序而言真实太方便了,通过http的交互方式,我们就可以进入性能分析的界面。

开启pprof

pprof可以支持单机程序和server项目,单机程序的话我们需要在程序里面硬编码,通过的打点的方式告诉pprof采集CPU、内存等文件,然后文件会落入指定的路径最终进行分析。但是我们实际开发场景大都是server项目,所以这里我也以server项目来举例说明。

1、Go原生的http服务框架

当采用go原生的http服务框架,使用pprof非常的简单:只需要导入net/http/pprof包即可。代码如下:

package mainimport ("fmt""net/http"_ "net/http/pprof"
)func HelloWorld(w http.ResponseWriter, r *http.Request) {fmt.Fprintln(w, "hello world")
}func main() {http.HandleFunc("/", HelloWorld)err := http.ListenAndServe(":8080", nil)if err != nil {fmt.Println(err)}
}

2、使用gin框架实现的服务

这个也是我们常用的一种方式,Gin框架如果要添加pprof, 可以借助github.com/gin-contrib/pprof包,并且在项目启动的入口位置注册一下pprof,代码如下:

package routersimport ("github.com/gin-contrib/pprof""github.com/gin-contrib/pprof"  //引入gin对应的pprof包"github.com/gin-gonic/gin""go-server/app/controller"
)func init() {//创建一个gin示例router := gin.Default()pprof.Register(router)  //注册pprof//注册路径user := router.Group("/performance"){user.GET("/pertest", controller.CollectPerformance)}//监听端口router.Run(":8080")
}

server类型的项目,启动之后出现如下日志说明注册pprof成功:

浏览器中访问:localhost:8080/debug/pprof

 

各项指标说明:

pprof分析 

性能分析

性能分析主要是分析程序的耗时情况,这个在pprof是采集CPU的信息,在CPU的采集信息里会有每个函数占用CPU片段的时间,这个也间接的反应了函数的耗时时长。

通过上面这些步骤开启pprof之后,接下来我们就要进行数据的采集,pprof并不是默认采集数据的,而是需要手动去采集一段时间的性能数据(默认是30s),所以开启这个不需要担心会对系统造成负担,只要不主动采集,pprof是不会进行工作。

开启CPU采集通过访问url地址:http://<host>:<port>/debug/pprof/profile,可以带参数?seconds = 60表示采集60s,访问这个地址之后,程序会block住等待一定的时间,在这个时间内我们进行的操作就会被采集进去,一般采用交互式命令的方式开启采集:

go tool pprof http://<host>:<port>/debug/pprof/profile

开启采集之后我们就可以立即访问需要测试的程序,然后采集数据,在本示例中我通过一个接口来模拟数据:

访问http://localhost:8080/performance/pertest地址会调用CollectPerformance这个函数,在这个函数中调用了另外一个耗时函数:

func CollectPerformance(ctx *gin.Context) {performanceWait()  //这是一个耗时函数
}func performanceWait() {for i := 2000000; i >= 0; i-- {fmt.Println(i)}
}

访问程序之后,pprof的交互界面经过默认的采集时间之后就可以进行查看数据了,下面就是分析阶段了:

1、top n 按照函数耗时排序,展示前多少个

这里重点看cum这个值,这个值表示的是函数本身执行的时间和调用其他函数的时间,我们可以直接按照cum来排序,top 20 -cum

各项指标说明:

 

2、list

list命令有点类似于arthas中的trace,可以列出程序的具体的耗时信息,比如上面我看到performanceWait这个函数耗时较长,那么通过list去看一下:

上面看到在20行消耗的cpu时间片最长,因为这里有一个很大的循环

注意:

  • pprof采集的数据是这段时间的总和,比如上面的1.35s表示这段时间程序执行时间的总和,不是平均值
  • 上述时间是函数CPU的时间,不一定是函数真实的运行时间,比如在函数里有一行time.sleep(13 * time.Second),这个时间并不会计算进去

 

 

内存分析

内存分析这里我们主要是分析堆内存,也是我们平时程序作用的地方。pprof提供了堆内存的检测方式,可以通过实施快照的方式帮助我们dump内存数据并且进行分析。

dump堆内存:go tool pprof http://localhost:6060/debug/pprof/heap

访问上面的地址pprof就会dump出当时的堆内存情况,这个和cpu的prfile不一样,不是执行完就block住等待数据产生,而是直接dump出执行时间点的堆内存信息

 我在接口中编写一个不断申请内存的程序,导致最终内存溢出,通过文件进行分析。

func CollectHeap(ctx *gin.Context) {tick := time.Tick(time.Second)var buf []bytestime := time.Now()for range tick {// 1秒1M内存buf = append(buf, make([]byte, 1024*1024)...)fmt.Printf("%f\n", time.Now().Sub(stime).Seconds())}
}

访问接口让程序执行,然后通过heap快照内存后进行分析,分析的方式和cpu一样,也是top和list命令:

执行top可以看到CollectHeap这个函数占用内存很高,通过list可以定位到具体的哪一行

再测试一个大对象占用的场景,在函数里定义一个map,循环往里面放数据。

package controllerimport ("fmt""github.com/gin-gonic/gin""github.com/google/uuid""go-server/app/models""time"
)var userMap = map[string]models.User{}func CollectHeap(ctx *gin.Context) {for i := 1000000; i >= 0; i-- {uuid := uuid.New().String()user := models.User{Name: uuid,Age:  i,}userMap[uuid] = user}
}

访问接口执行程序,然后看下堆内存情况

通过top可以看到在CollectHeap函数中有内存占用比较大

通过list可以看到在map赋值这一行占用内存最多,这里有一点和Java不太一样,就是pprof的分析都是基于函数为基础,所有所有的都显示到函数执行上,比如Java的内存分析会直接分析到对象,某个具体的map,但是Go里面还是对应函数执行,会有一点点不直观

 goroutine分析

分析goroutine主要是分析阻塞这种情况,比如系统中存在大量的goroutine没有执行完,导致泄露

代码示例:

func CollectGoroutine(ctx *gin.Context) {outCh := make(chan int) //无缓冲channelstime := time.Now()// 每1s个goroutinefor {time.Sleep(1 * time.Second)go alloc(outCh)fmt.Printf("last: %dseconds\n", int(time.Now().Sub(stime).Seconds()))}
}// alloc分配1M内存,goroutine会阻塞,不释放内存,导致泄漏
func alloc(outCh chan<- int) {buf := make([]byte, 1024*1024*1)_ = len(buf)fmt.Println("alloc make buffer done")outCh <- 0fmt.Println("alloc finished")
}

访问接口会不断开启goroutine分配内存,并且系统中的goutinue数量会不断上升,具体分析如下:

pprof分析goroutine推荐使用web界面访问的方式,这种访问也是实时的,每次访问都是实时的快照系统中的gotoutine情况,有两种分析方式:

1、goroutine总览:http://localhost:8080/debug/pprof/goroutine?debug=1

在goroutine总览里面可以看到系统中存在的goroutine数量,通过实时刷新我们可以看到这个数值在直线上升,说明肯定有阻塞的地方,导致goroutine没有释放,通过第二种方式查看明细

1、goroutine明细:http://localhost:8080/debug/pprof/goroutine?debug=2

明细里面会展示所有状态的goroutine情况

running状态:

 

sleep状态:

我们在代码41行执行了sleep的方法

block状态:

这里可以看到有很多线程都是阻塞在chan的发送上面,耗时几分钟,这里也列了代码中阻塞在哪一行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/216688.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Stm32-使用TB6612驱动电机及编码器测速

这里写目录标题 起因一、电机及编码器的参数二、硬件三、接线四、驱动电机1、TB6612电机驱动2、定时器的PWM模式驱动电机 五、编码器测速1、定时器的编码器接口模式2、定时器编码器模式测速的原理3、编码器模式的配置4、编码器模式相关代码5、测速方法 六、相关问题以及解答1、…

Python自动化测试工具selenium使用指南

概述 selenium是网页应用中最流行的自动化测试工具&#xff0c;可以用来做自动化测试或者浏览器爬虫等。官网地址为&#xff1a;相对于另外一款web自动化测试工具QTP来说有如下优点&#xff1a; 免费开源轻量级&#xff0c;不同语言只需要一个体积很小的依赖包支持多种系统&a…

基于OpenCV+CNN+IOT+微信小程序智能果实采摘指导系统——深度学习算法应用(含python、JS工程源码)+数据集+模型(二)

目录 前言总体设计系统整体结构图系统流程图 运行环境Python环境TensorFlow 环境Jupyter Notebook环境Pycharm 环境微信开发者工具OneNET云平台 相关其它博客工程源代码下载其它资料下载 前言 本项目基于Keras框架&#xff0c;引入CNN进行模型训练&#xff0c;采用Dropout梯度…

鸿蒙系统最近删除文件夹的路径

鸿蒙手机上删除文件&#xff0c;会将文件移动到类似回收站的路径下&#xff0c;如何找到这个路径&#xff1f; 先找用文件管理器找到一个文件 比如aaa.jpg &#xff0c;这时在调试的shell下面运行 find . -name aaaa.jpg 得到如下 这时再删除该文件 再次运行 find . -name a…

【JUC】二十五、ThreadLocal内存泄漏问题(强软弱虚四种引用)

文章目录 1、引用之强软弱虚2、强引用3、软引用4、弱引用5、虚引用6、ThreadLocal回顾7、ThreadLocal使用弱引用的原因8、清除脏Entry9、最佳实践 不再会被使用的对象或者变量占用的内存不能被回收&#xff0c;就是内存泄露&#xff08;累积可能导致OOM&#xff09;。 1、引用之…

InnoDB在SQL查询中的关键功能和优化策略

文章目录 前言存储引擎介绍存储引擎是干嘛的InnoDB的体系结构 InnoDB的查询操作InnoDB的查询原理引入 Buffer Pool引入数据页Buffer Pool 的结构数据页的加载Buffer Pool 的管理Buffer Pool 的优化 总结 前言 通过上篇文章《MySQL的体系结构与SQL的执行流程》了解了SQL语句的执…

【LSM tree 】Log-structured merge-tree 一种分层、有序、面向磁盘的数据结构

文章目录 前言基本原理读写流程写流程读流程 写放大、读放大和空间放大优化 前言 LSM Tree 全称是Log-structured merge-tree, 是一种分层&#xff0c;有序&#xff0c;面向磁盘的数据结构。其核心原理是磁盘批量顺序写比随机写性能高很多&#xff0c;可以通过围绕这一原理进行…

scala表达式

1.8 表达式&#xff08;重点&#xff09; # 语句(statement)&#xff1a;一段可执行的代码# 表达式(expression)&#xff1a;一段可以被求值的代码&#xff0c;在Scala中一切都是表达式 - 表达式一般是一个语句块&#xff0c;可包含一条或者多条语句&#xff0c;多条语句使用“…

Android BluetoothAdapter 使用(二)

Android BluetoothAdapter 使用(二) 本篇文章主要讲下蓝牙设备的配对. 1: 蓝牙设备列表展示 下 面是蓝牙设备adapter的代码: package com.test.bluetooth;import android.bluetooth.BluetoothDevice; import android.content.Context; import android.view.LayoutInflater;…

Linux中的堡垒机搭建以及使用

JumpServer搭建 安装应用包 curl -sSL https://resource.fit2cloud.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash 一路回车即可安装完毕&#xff08;可根据需求更改&#xff09; JumpServer的 配置文件路径 /opt/jumpserver/config/config.tx…

【智能家居】九、停车场车牌识别功能点(回调、解耦)

一、翔云 人工智能开放平台&#xff08;车牌识别&#xff09; 二、cJSON 库 三、实现代码 四、回调函数 五、人脸识别和车牌识别获取数据的区别 六、异步网络请求和同步网络请求的区别 七、解耦 一、翔云 人工智能开放平台&#xff08;车牌识别&#xff09; 翔云 人工智能开放…

.NET 反射优化的经验分享

比如针对 GetCustomAttributes 通过反射获取属性的优化,以下例子 // dotnet run -c Release -f net7.0 --filter "*" --runtimes net7.0 net8.0public class Tests{public object[] GetCustomAttributes() => typeof(C).GetCustomAttributes(typeof(MyAttribute…

坑爹的奥数(枚举法)

枚举法是一种解决问题的基本方法&#xff0c;它通过列举问题的所有可能情况来找到问题的解。这种方法适用于问题的解空间相对较小&#xff0c;可以通过穷举所有可能的解来找到最优解或满足特定条件的解。 以下是枚举法的一般步骤&#xff1a; 定义问题&#xff1a; 确定问题的…

Cypress安装与使用教程(2)—— 软测大玩家

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

数据库字段名和sql关键字冲突报错解决方法

1、修改实体类字段映射。注解里加反引号 2、sql字段上加反引号 3、问题解决

ue5材质预览界面ue 变黑

发现在5.2和5.1上都有这个bug 原因是开了ray tracing引起的&#xff0c;这个bug真是长时间存在&#xff0c;类似的bug还包括草地上奇怪的影子和地形上的影子等等 解决方法也很简单&#xff0c;就是关闭光追&#xff08;不是…… 就是关闭预览&#xff0c;在材质界面preview sc…

C# WPF上位机开发(会员充值软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在软件开发中&#xff0c;有一种很重要的控件&#xff0c;那就是表格。大家可以想象下&#xff0c;办公软件里面是不是就有一个专门做表格的软件&a…

路由器的转换原理--ENSP实验

目录 一、路由器的工作原理 二、路由表的形成 1、直连路由 2、非直连路由 2.1静态路由 2.2动态路由 三、静态路由和默认路由 1、静态路由 1.1静态路由的缺点 1.2路由的配置--结合ensp实验 2、默认路由--特殊的静态路由 2.1概念 2.2格式 2.3默认路由的配置--ens…

本地部署语音转文字(whisper,SpeechRecognition)

本地部署语音转文字 1.whisper1.首先安装Chocolatey2.安装3.使用 2.SpeechRecognition1.环境2.中文包3.格式转化4.运行 3.效果 1.whisper 1.首先安装Chocolatey https://github.com/openai/whisper 以管理员身份运行PowerShell Set-ExecutionPolicy Bypass -Scope Process -…

LeetCode刷题--- 二叉树剪枝

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏&#xff1a;http://t.csdnimg.cn/ZxuNL http://t.csdnimg.cn/c9twt 前言&#xff1a;这个专栏主要讲述递归递归、搜索与回溯算法&#xff0c;所以下面题目主要也是这些算法做的 我讲述…