Golang中的pprof分析环境搭建【Windows环境】
一、pprof简介
- pprof,是golang 自带性能剖析工具,可以帮助定位程序中可能存在的问题,是go服务程序异常时辅助排查问题的有效工具
- Graphviz是开源的图形可视化软件。图形可视化是一种将结构信息表示为抽象图形和网络图的方法。它在网络,生物信息学,软件工程,数据库和网页设计,机器学习以及其他技术领域的可视化界面中具有重要的应用。
二、依赖工具
- graphviz图形可视化工具:https://download.youkuaiyun.com/download/weixin_43563169/84397206
- go环境
三、服务集成【Gin框架】
package main
import (
"github.com/gin-gonic/gin"
"github.com/DeanThompson/ginpprof"
)
func main() {
router := gin.Default()
// automatically add routers for net/http/pprof
// e.g. /debug/pprof, /debug/pprof/heap, etc.
ginpprof.Wrap(router)
// ginpprof also plays well with *gin.RouterGroup
// group := router.Group("/debug/pprof")
// ginpprof.WrapGroup(group)
}
-
如果需要自定义封装采集,可以参考net/http/pprof中的init使用
// net/http/pprof func init() { http.HandleFunc("/debug/pprof/", Index) http.HandleFunc("/debug/pprof/cmdline", Cmdline) http.HandleFunc("/debug/pprof/profile", Profile) http.HandleFunc("/debug/pprof/symbol", Symbol) http.HandleFunc("/debug/pprof/trace", Trace) }
-
封装一个采集器,参考:一文搞懂pprof - 墨天轮 (modb.pro)
// 采集注册 将gin路由注册进来即可 // Register the standard HandlerFuncs from the net/http/pprof package with // the provided gin.Engine. prefixOptions is a optional. If not prefixOptions, // the default path prefix is used, otherwise first prefixOptions will be path prefix. func Register(r *gin.Engine, prefixOptions ...string) { RouteRegister(&(r.RouterGroup), prefixOptions...) } // RouteRegister the standard HandlerFuncs from the net/http/pprof package with // the provided gin.GrouterGroup. prefixOptions is a optional. If not prefixOptions, // the default path prefix is used, otherwise first prefixOptions will be path prefix. func RouteRegister(rg *gin.RouterGroup, prefixOptions ...string) { prefix := getPrefix(prefixOptions...) prefixRouter := rg.Group(prefix) { prefixRouter.GET("/", pprofHandler(pprof.Index)) prefixRouter.GET("/cmdline", pprofHandler(pprof.Cmdline)) prefixRouter.GET("/profile", pprofHandler(pprof.Profile)) prefixRouter.POST("/symbol", pprofHandler(pprof.Symbol)) prefixRouter.GET("/symbol", pprofHandler(pprof.Symbol)) prefixRouter.GET("/trace", pprofHandler(pprof.Trace)) prefixRouter.GET("/allocs", pprofHandler(pprof.Handler("allocs").ServeHTTP)) prefixRouter.GET("/block", pprofHandler(pprof.Handler("block").ServeHTTP)) prefixRouter.GET("/goroutine", pprofHandler(pprof.Handler("goroutine").ServeHTTP)) prefixRouter.GET("/heap", pprofHandler(pprof.Handler("heap").ServeHTTP)) prefixRouter.GET("/mutex", pprofHandler(pprof.Handler("mutex").ServeHTTP)) prefixRouter.GET("/threadcreate", pprofHandler(pprof.Handler("threadcreate").ServeHTTP)) } } func pprofHandler(h http.HandlerFunc) gin.HandlerFunc { handler := http.HandlerFunc(h) return func(c *gin.Context) { handler.ServeHTTP(c.Writer, c.Request) } }
四、使用示例
-
新建一个gin服务
r := gin.New()
-
注册采集器,明确服务端口
registerPprof(r) r.GET(aliveURI, c.aliveHandle()) //示例,aliveURI和c.aliveHandle()换成各自的url和响应函数即可
-
打包部署【这里不写打包流程,,贴完整代码】
-
main.go
package main import ( "github.com/gin-gonic/gin" "github.com/DeanThompson/ginpprof" ) func main() { //gin 路由初始化 r := gin.New() // 注册pprof self_pprof.RegisterPprof(r) //gin 路由初始化 apiG := r.Group("/api") r.GET("/hello", restful.Hello) //开启监听服务端口 err := r.Run(":8089") if err != nil { return nil } }
-
restful.go
package restful import "github.com/gin-gonic/gin type response struct { Code int `json:"code"` Msg string `json:"msg"` Data interface{} `json:"data,omitempty"` } // Hello func Hello(c *gin.Context) { c.JSON(http.StatusOK, response{ Code: 200, Msg: "success", Data: "hello", }) return }
-
self_pprof.go
package self_pprof // copy from https://github.com/gin-contrib/pprof/blob/master/pprof.go import ( "net/http" "net/http/pprof" "github.com/gin-gonic/gin" ) const ( // DefaultPrefix url prefix of pprof DefaultPrefix = "/debug/pprof" ) func getPrefix(prefixOptions ...string) string { prefix := DefaultPrefix if len(prefixOptions) > 0 { prefix = prefixOptions[0] } return prefix } // RegisterPprof the standard HandlerFuncs from the net/http/pprof package with // the provided gin.Engine. prefixOptions is a optional. If not prefixOptions, // the default path prefix is used, otherwise first prefixOptions will be path prefix. func RegisterPprof(r *gin.Engine, prefixOptions ...string) { RouteRegister(&(r.RouterGroup), prefixOptions...) } // RouteRegister the standard HandlerFuncs from the net/http/pprof package with // the provided gin.GrouterGroup. prefixOptions is a optional. If not prefixOptions, // the default path prefix is used, otherwise first prefixOptions will be path prefix. func RouteRegister(rg *gin.RouterGroup, prefixOptions ...string) { prefix := getPrefix(prefixOptions...) prefixRouter := rg.Group(prefix) { prefixRouter.GET("/", pprofHandler(pprof.Index)) prefixRouter.GET("/cmdline", pprofHandler(pprof.Cmdline)) prefixRouter.GET("/profile", pprofHandler(pprof.Profile)) prefixRouter.POST("/symbol", pprofHandler(pprof.Symbol)) prefixRouter.GET("/symbol", pprofHandler(pprof.Symbol)) prefixRouter.GET("/trace", pprofHandler(pprof.Trace)) prefixRouter.GET("/allocs", pprofHandler(pprof.Handler("allocs").ServeHTTP)) prefixRouter.GET("/block", pprofHandler(pprof.Handler("block").ServeHTTP)) prefixRouter.GET("/goroutine", pprofHandler(pprof.Handler("goroutine").ServeHTTP)) prefixRouter.GET("/heap", pprofHandler(pprof.Handler("heap").ServeHTTP)) prefixRouter.GET("/mutex", pprofHandler(pprof.Handler("mutex").ServeHTTP)) prefixRouter.GET("/threadcreate", pprofHandler(pprof.Handler("threadcreate").ServeHTTP)) } } func pprofHandler(h http.HandlerFunc) gin.HandlerFunc { handler := http.HandlerFunc(h) return func(c *gin.Context) { handler.ServeHTTP(c.Writer, c.Request) } }
-
五、测试
-
如果是本地,直接访问自己的服务端口,例如
-
如果是线上服务器
本文采用rpm包部署,部署完成后,项目路径下executor.sock会记录服务端口,当然自己应该也知道 如果部署在服务器上,没有GUI界面,可以将profile文件下载后,本地使用go tool pprof查看分析,具体使用如下
-
1、登录linux服务器,执行profile文件下载
//31301是本文服务的端口 wget -O goroutine http://localhost:31301/debug/pprof/goroutine wget -O heap http://localhost:31301/debug/pprof/heap wget -O trace http://localhost:31301/debug/pprof/trace ...
-
2、本地go tool分析
go tool pprof -http=":8082" goroutine go tool trace -http=":8083" trace go tool pprof -http=":8081" heap ...
-
3、本地浏览器访问
-