前言
声明: 本文不对pprof基础做讲解,详情可以查阅 https://studygolang.com/pkgdoc 找到net/http/pprof
golang pprof官方介绍里,是采用了默认6060端口,单独开辟了应用进程的pprof服务。它在生产中有以下问题:
- 需要额外维护不同应用组的pprof端口。(实际上,它可以和业务绑定在同一个路由端口里,减少端口冲突维护)。
- 在二次开发上,可能想接入鉴权,限频的拦截,官方提供的方式做不到。
- 官方的路由是f(w http.Writer, r *http.Request),而项目里,可能用到了gin,难以接入。
解决
实现
从gin项目来演示如何让pprof和业务绑定同端口。
本代码片段,为可复制片段,按照项目鉴权等自行适配
func profRouter(r gin.IRoutes) {
// 主页面
r.GET("/debug/pprof/", adapt(pprof.Index))
r.GET("/debug/pprof/profile", profile())
r.GET("/debug/pprof/heap", heap())
r.GET("/debug/pprof/block", block())
r.GET("/debug/pprof/goroutine", goroutine())
r.GET("/debug/pprof/allocs", allocs())
r.GET("/debug/pprof/cmdline", cmdline())
r.GET("/debug/pprof/threadcreate", threadcreate())
r.GET("/debug/pprof/mutex", mutex())
r.GET("/debug/pprof/trace", trace())
}
func adapt(f func(w http.ResponseWriter, r *http.Request)) func(c *gin.Context) {
return func(c *gin.Context) {
f(c.Writer, c.Request)
}
}
func profile() gin.HandlerFunc {
return adapt(pprof.Profile)
//return adapt(pprof.Handler("profile").ServeHTTP)
}
func heap() gin.HandlerFunc {
return adapt(pprof.Handler("heap").ServeHTTP)
}
func block() gin.HandlerFunc {
return adapt(pprof.Handler("block").ServeHTTP)
}
func goroutine() gin.HandlerFunc {
return adapt(pprof.Handler("goroutine").ServeHTTP)
}
func allocs() gin.HandlerFunc {
return adapt(pprof.Handler("allocs").ServeHTTP)
}
func cmdline() gin.HandlerFunc {
return adapt(pprof.Cmdline)
}
func threadcreate() gin.HandlerFunc {
return adapt(pprof.Handler("threadcreate").ServeHTTP)
}
func mutex() gin.HandlerFunc {
return adapt(pprof.Handler("mutex").ServeHTTP)
}
func trace() gin.HandlerFunc {
return adapt(pprof.Trace)
}
func main(){
r := gin.Default()
// pprof路由
profRouter(r)
// 业务路由
xxx(r)
r.Run(":8080")
}
代码中,使用了进行转换,使官方的路由可以适配进来
func adapt(f func(w http.ResponseWriter, r *http.Request)) func(c *gin.Context) {
return func(c *gin.Context) {
f(c.Writer, c.Request)
}
}
效果和官方保持一致
http://localhost:8080/debug/pprof/
另外,如果pprof的视图很乱,想要了解两个服务增量上的差异,可以使用
go tool pprof -base file1 file2 来比较增量差异。
其中file1和file2是通过类似以下命令拉取的分析文件
curl http://localhost:9112/local/api/debug/pprof/goroutine > file2
仓库
该实现,已经开源到https://github.com/fwhezfwhez/ginprof.git
import "github.com/fwhezfwhez/ginprof"
func main() {
router := gin.New()
ginprof.ProfRouter(router)
...
}