Golang中的pprof分析环境搭建【Windows环境】

Golang中的pprof分析环境搭建【Windows环境】

一、pprof简介

  • pprof,是golang 自带性能剖析工具,可以帮助定位程序中可能存在的问题,是go服务程序异常时辅助排查问题的有效工具
  • Graphviz是开源的图形可视化软件。图形可视化是一种将结构信息表示为抽象图形和网络图的方法。它在网络,生物信息学,软件工程,数据库和网页设计,机器学习以及其他技术领域的可视化界面中具有重要的应用。

二、依赖工具

  • graphviz图形可视化工具:https://download.csdn.net/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)
      	}
      }
      

五、测试

  • 如果是本地,直接访问自己的服务端口,例如

    • /debug/pprof/
    • 效果:Golang中的pprof分析环境搭建【Windows环境】_第1张图片
      Golang中的pprof分析环境搭建【Windows环境】_第2张图片
  • 如果是线上服务器

    本文采用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、本地浏览器访问

      Golang中的pprof分析环境搭建【Windows环境】_第3张图片
      Golang中的pprof分析环境搭建【Windows环境】_第4张图片
      Golang中的pprof分析环境搭建【Windows环境】_第5张图片

你可能感兴趣的:(golang,开发语言,后端)