此工具主要是用来采样、分析各链路上的各种指标数据以分析应用性能瓶颈的
就目前而言 大概 10ms
会采样一次各项数据
采集的这个数据,下文我们称之为 profiling
数据
获取的 profiling
数据是动态的
要想获得有效的数据,请保证应用处于较大的负载(比如正在生成中运行的服务,或者通过其他工具模拟访问压力)
否则如果应用处于空闲状态,得到的结果可能没有任何意义
如果是 API
性能问题
一般可以通过本地使用 wrk 进压测
或者 预发布环境
配合 access_log
进行 流量回放
请注意,检测后请及时下掉这个 pprof
包
请尽量不要引入到生产环境
以免被外面的人恶意使用
引入包 net/http/pprof
package http
import (
"github.com/gin-gonic/gin"
"net/http/pprof"
"node_puppeteer_example_go/api/service"
)
var srv *service.Service
func Init(e *gin.Engine, srvInjection *service.Service) *gin.Engine {
srv = srvInjection
//e.Use() // 暂无中间件需要被设置
{
comic := &Comic{}
/**
* 用户端API
* TODO 接口级缓存
*/
routeComic := e.Group("api/")
routeComic.GET("comic/list", comic.GetList)
routeComic.GET("chapter/list", comic.GetChapterList)
routeComic.GET("chapter/detail", comic.GetChapterDetail)
routeComic.GET("image/list", comic.GetImageList)
}
{
// 注入debug信息到router
routerDebug := e.Group("/hlzblog_debug") // 这个group的命中自定义就可以了
routerDebug.GET("/", func(c *gin.Context) {
pprof.Handler("index").ServeHTTP(c.Writer, c.Request)
})
routerDebug.GET("/heap", func(c *gin.Context) {
pprof.Handler("heap").ServeHTTP(c.Writer, c.Request)
})
routerDebug.GET("/goroutine", func(c *gin.Context) {
pprof.Handler("goroutine").ServeHTTP(c.Writer, c.Request)
})
routerDebug.GET("/allocs", func(c *gin.Context) {
pprof.Handler("allocs").ServeHTTP(c.Writer, c.Request)
})
routerDebug.GET("/block", func(c *gin.Context) {
pprof.Handler("block").ServeHTTP(c.Writer, c.Request)
})
routerDebug.GET("/threadcreate", func(c *gin.Context) {
pprof.Handler("threadcreate").ServeHTTP(c.Writer, c.Request)
})
routerDebug.GET("/cmdline", func(c *gin.Context) {
pprof.Handler("cmdline").ServeHTTP(c.Writer, c.Request)
})
routerDebug.GET("/profile", func(c *gin.Context) {
pprof.Handler("profile").ServeHTTP(c.Writer, c.Request)
})
routerDebug.Any("/symbol", func(c *gin.Context) {
pprof.Handler("symbol").ServeHTTP(c.Writer, c.Request)
})
routerDebug.GET("/trace", func(c *gin.Context) {
pprof.Handler("trace").ServeHTTP(c.Writer, c.Request)
})
routerDebug.GET("/mutex", func(c *gin.Context) {
pprof.Handler("mutex").ServeHTTP(c.Writer, c.Request)
})
}
return e
}
当然,你也可以看看云天河在生产环境的集成示例 点此查看
其中我们通常需要观察的几个路由如下
/hlzblog_debug/profile:访问这个链接会自动进行 CPU profiling,持续 30s,并生成一个文件供下载
/hlzblog_debug/heap: Memory Profiling 的路径,访问这个链接会得到一个内存 Profiling 结果的文件
/hlzblog_debug/block:block Profiling 的路径
/hlzblog_debug/goroutines:运行的 goroutines 列表,以及调用关系
如果你当初发现性能瓶颈的场景
能在本地通过 wrk
直接压测复现
那么你现在可以先 wrk
执行起来了
示例,我本地压测漫画列表 API
条件名 | 对应值 | 备注 |
---|---|---|
线程数 | 8个 | - |
并发连接数 | 50个 | - |
压测时长 | 20分钟 | 主要是想边测边看 |
wrk -t8 -c50 -d 20m 'http://192.168.56.110:2333/api/comic/list?page=1'
示例 如图 01
图 01
采集打点前,了解各项指标含义
router后缀 | 打点指标介绍 |
---|---|
allocs | 内存分配情况的采样信息 |
blocks | 阻塞操作情况的采样信息 |
cmdline | 显示程序启动命令及参数 |
goroutine | 当前所有协程的堆栈信息 |
heap | 存活对象内存使用情况的采样信息 |
mutex | 锁争用情况的采样信息 |
profile | CPU 占用情况的采样信息 |
threadcreate | 系统线程创建情况的采样信息 |
trace | 程序运行跟踪信息 |
调整 http
服务的 writeTimeout
的时间
稍微超过读取 profiling
的时间即可
比如,现在我计划采样 30s
多设置几秒,比如我这里多设置 5s
httpServer:
name: node_puppeteer_example_go_api
ip: 0.0.0.0
port: 2333
readTimeout: 3s
writeTimeout: 35s
maxHeaderBytes: 1048576
在进行压测的期间,进行 profiling
数据读取
并对读取下载后的进行图形绘制
比如,本次我计划采集的是内存相关数据
通过 pprof
配合图形化工具 graphviz 动态查看
示例在ubutu
上 安装
apt install graphviz
安装好后就可以以图形化工具查看打点指标数据了
指定本地专门用来看打点数据的监听地址,比如 0.0.0.0:8081
本地的指标数据路由 http://192.168.56.110:2333/hlzblog_debug/heap
默认是 30s
你可以在 url 参数后面加queryString
设置采集时间,如 seconds=30
go tool pprof -http=0.0.0.0:8081 "http://192.168.56.110:2333/hlzblog_debug/heap?seconds=30"
这个过程简单描述下
pprof
工具会先打点下载对应指标的 profiling
数据
然后再通过本地读取对应 pb
数据即可绘制 UI
, 如 图 02-1
图 02-1
刚刚命令中的链接 http://192.168.56.110:2333/hlzblog_debug/heap?seconds=30
此后就可以直接换成pb
文件地址也可以直接看 UI
渲染解雇了 图 02-2
图 02-2
本地就可以访问 8081
端口呈现出 UI
效果
比较常用的就是火焰图
了
如 图 02-3
方式选中 VIEW
-Flame Graph
图 02-3
火焰图的 Y轴
表示cpu调用方法的先后(从root开始)
X轴
表示在每个采样调用时间内
方法所占对应指标数据
的百分比
越宽
代表占据对应指标数据
越多
通过火焰图我们就可以更清楚的找出对应指标数据
占比较高的函数调用
然后不断的修正代码 重新采样 不断去优化
比如这里的指标数据是内存
我们可以看到
curl_avatar.(*Dao).SupplierList
这个方法,占用的内存较高
这时候就可以分析是否为内存瓶颈
同理,可以使用采集及其指标进行分析
这个一般是想把 方式1
中采集到的火焰图导出来
下载生成图形的工具 FlameGraph
然后将其解压后的目录加入环境变量
安装 go-touch
go get -v github.com/uber/go-torch
# 打点记录 30秒 堆栈信息
go-torch -u http://192.168.56.110:2333 --suffix=hlzblog_debug/heap -t 30 --colors mem -f mem.svg
其中
-u
表示对应指标数据采集地址
--suffix=
表示采集的数据路由
-t
表示采集秒数
-f
表示采集生成的对应 SVG数据
存储到哪里
--colors
表示生成的 SVG图片
主题样式
生成的文件,如 图 03
所示
图 03
生成的内容,如 图 04
所示
图 04
评论列表点此评论