写点什么

Go: gops 如何与 Go 运行时交互?

用户头像
陈思敏捷
关注
发布于: 2020 年 09 月 06 日
Go: gops如何与Go运行时交互?

ℹ️ 本文基于Go1.13和gops 0.3.7



gops致力于帮助开发者诊断Go进程并与之交互。它提供跟踪运行中程序数秒,通过pprof获取CPU分析数据,甚至可以直接和GC交互的能力。



发现

gops提供了一种发现服务,该服务可以罗列出计算机上运行的Go进程。不带参数的运行gops仅显示Go进程。为了举例说明,我启动了一个计算高达一百万素数的程序。这是输出结果:



295 1 gops go1.13 /go/src/github.com/google/gops/gops
168 1 prime-number* go1.13 /go/prime-number/prime-number



gops发现了上面启动的程序和自己本身的进程。让我们先来了解下gops如何过滤Go进程。



首先,gops列出所有的进程。然后对于每个进程,它打开二进制文件读取符号表:





如果符号表包含runtime.main (主goroutine入口)或者 main.main (我们程序的入口),它会被标记成Go程序。



如果想了解更多主goroutine,建议阅读之前的文章  Go: g0, 特殊的goroutine



gops还可以通过阅读符号表里runtime.buildVersion 来获取使用的Go版本。但是,由于可以从二进制中删除符号表,所以gops需要另一种方式来检测Go二进制文件。让我们用删除符号表后的二进程文件再试一次:



295 1 gops go1.13 /go/src/..../gops
168 1 prime-number-s* unknown Go version /go/.../prime-number-s



程序能够被正确的标识为Go二进制文件,但是因为缺少符号表而不能检测出Go版本。根据ELF,MZ等可执行文件格式,gops会读取各段来查找嵌在二进制文件中的构建ID。一旦发现流程结束,它就可以开始与程序交互。



交互

与其他Go程序进行交互的唯一条件是确保它们启动gops代理。 该代理是一个简单的监听器,将为gops请求提供服务。 只需添加以下行即可:

if err := agent.Listen(agent.Options{}); err != nil {
log.Fatal(err)
}



然后,任何启动了代理的程序都可以和gops交互。这里是执行stats命令的例子:

# gops stats 168
goroutines: 6210
OS threads: 9
GOMAXPROCS: 2
num CPU: 2



更多命令,你可以查阅官方手册。如果代理缺失,你将会在交互时收到一个报错:

Couldn't resolve addr or pid 168 to TCPAddress: couldn't get port for PID 168

该错误表明gops通过TCP寻找暴露的端口以便与程序进行交互。让我们画出这个包的工作流来了解它。



工作流

gops与要读取的程序之间的通信是通过TCP和程序暴露的端口来完成的:





分配给每个程序的端口都写在一个配置文件中,例如 path/to/config/{processID} ,这使得 gops 很容易知道暴露的端口。然后,gops 可以将命令标识发送给程序,代理 将会收集数据并响应:





编译自:https://medium.com/a-journey-with-go/go-how-does-gops-interact-with-the-runtime-778d7f9d7c18

博客地址:https://www.chenjie.info/2607





发布于: 2020 年 09 月 06 日阅读数: 51
用户头像

陈思敏捷

关注

多动脑不痴呆 2017.12.21 加入

gopher

评论

发布
暂无评论
Go: gops如何与Go运行时交互?