Go诊断工具gops

好久没写博客了,最近遇到个调试线上go服务的小问题,特此记录一下。

大家都知道gops是一个列出和诊断Go进程的工具, 它的使用命令如下:

gops <cmd> <pid|addr> ...
gops <pid> 列出进程信息(包括非Go的进程)

cmd 主要有以下几个

stack       	打印当前调用栈
gc          	立即运行gc(会一直阻塞直到成功)
setgc	        设置GC百分比
memstats    	打印内存信息统计
version     	打印运行程序go版本
stats       	打印运行时信息统计.

trace       	trace 5s 然后运行go tool trace
pprof-heap  	读取堆内存剖析信息然后运行go tool pprof
pprof-cpu   	读取cpu剖析信息然后运行go tool pprof

gops支持进程id和远程两种方式

使用时只需要在go程序中嵌入agent即可

import (
    "log"

    "github.com/google/gops/agent"
)
if err := agent.Listen(agent.Options{}); err != nil {
    log.Fatal(err)
}

本地方式

如上代码启动时会在localhost监听一个随机端口,本地调试时使用gops <cmd> <pid>这些命令完全够用了。

远程方式

由于我们的服务全部跑在容器里,这样上面的gops需要改成远程的方式使用gops <cmd> <remote_addr>

然而就是在这里遇到问题了,默认的Options使用的addr只监听了lo网卡,也就是必须要在容器内才能执行gops,由于是线上环境,开发没有权限登到容器中执行这些,所以需要修改addr 监听所有网卡的指定端口如0.0.0.0:8001。再通过k8s的网络,只要在集群中任意一台节点上就可以使用远程调试了。

然而开发可用的跳板机上没有gops,我们把二进制文件拷贝到跳板机上后执行stack memstats这些信息已经没有问题了,但是在执行profiling相关的命令是总是不成功, 以trace为例,执行生成了trace文件后就结束了

./gops trace 10.244.16.224:8001
Tracing now, will take 5 secs...
Trace dump saved to: /tmp/trace371893560

正常还有类似这样的步骤日志

Parsing trace...
Splitting trace...
Opening browser. Trace viewer is listening on http://127.0.0.1:44365

通过查看gops help 看到trace命令的说明,生成了trace文件后会调用go tool trace命令,从gops源码也看到了这一点

If go tool chain not found, stopping here and keep trace file.

//cmd.go
func trace(addr net.TCPAddr, _ []string) error {
        fmt.Println("Tracing now, will take 5 secs...")
        out, err := cmd(addr, signal.Trace)
        if err != nil {
                return err
        }
        if len(out) == 0 {
                return errors.New("nothing has traced")
        }
        tmpfile, err := ioutil.TempFile("", "trace")
        if err != nil {
                return err
        }
        if err := ioutil.WriteFile(tmpfile.Name(), out, 0); err != nil {
                return err
        }
        fmt.Printf("Trace dump saved to: %s\n", tmpfile.Name())
        // If go tool chain not found, stopping here and keep trace file.
        if _, err := exec.LookPath("go"); err != nil {
                return nil
        }
        defer os.Remove(tmpfile.Name())
        cmd := exec.Command("go", "tool", "trace", tmpfile.Name())
        cmd.Env = os.Environ()
        cmd.Stdin = os.Stdin
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        return cmd.Run()
}

原来忘记跳板机上没有go了,反正要在浏览器上看,索性把文件拉到本地来看了

go tool trace -http=:6060 trace371893560
2021/03/25 16:20:19 Parsing trace...
2021/03/25 16:20:19 Splitting trace...
2021/03/25 16:20:19 Opening browser. Trace viewer is listening on http://[::]:6060

pprof-heappprof-cpu也类似,只会生成文件,也同样需要go tool命令来运行。

$ go tool pprof heap_profile589682544
$ go tool pprof cpu_profile077923742

wechat
微信扫一扫,订阅我的博客动态^_^