一 给项目加上 pprof

1 简单的 http 服务直接使用 _ "net/http/pprof"

package main

import (
	// 略
	_ "net/http/pprof" // 会自动注册 handler 到 http server,方便通过 http 接口获取程序运行采样报告
	// 略
)

func main() {
	// 略

	runtime.GOMAXPROCS(1) // 限制 CPU 使用数,避免过载
	runtime.SetMutexProfileFraction(1) // 开启对锁调用的跟踪
	runtime.SetBlockProfileRate(1) // 开启对阻塞操作的跟踪

	go func() {
		// 启动一个 http server,注意 pprof 相关的 handler 已经自动注册过了
		if err := http.ListenAndServe(":8023", nil); err != nil {
			log.Fatal(err)
		}
		os.Exit(0)
	}()

	// 略
}

2 gowork 项目使用 gin 框架的,pprof 使用 "github.com/DeanThompson/ginpprof"

package main

import (
    "github.com/gin-gonic/gin"

    "github.com/DeanThompson/ginpprof"
)

func main() {
    router := gin.Default()

    router.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })

    // automatically add routers for net/http/pprof
    // e.g. /debug/pprof, /debug/pprof/heap, etc.
    ginpprof.Wrapper(router)

    router.Run(":8023")
}

2 运行项目,可以在 http://localhost:8023/debug/pprof/goroutine?debug=1 看到输出的信息。

goroutine 泄露前.png

可以看到,刚开始协程 total:12, 然后做一些引起开协程并结束动作,看看协程的状态:

开 goroutine.png

这时协程已经失控了。

我们使用命令行 go 自带的工具命令

go tool pprof http://localhost:8023/debug/pprof/goroutine 会返回一个交互对话框,

这里使用 top, list ×××, web 命令查看具体信息

gotoolpproftop.png

list 具体某一条

gotoolpproflist.png

web 命令,虽然这个命令的名字叫“web”,但它的实际行为是产生一个 .svg 文件,并调用你的系统里设置的默认打开 .svg 的程序打开它。如果遇到 failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in $PATH 错误,需要安装 Graphviz ,ubuntu 下安装直接 sudo apt-get install graphviz。好了,我在软件中做了一些 ssh 的操作,这些操作会引起后台开启协程,在浏览器中会看到下图:

泄露的 gr.png

这里图片不是很清晰,主要想说明 pprof 调试确定协程泄露的方法。解决掉协程泄露失控的问题后,如下:

解决后.png