gops 是怎麼和 Go 的執行時進行互動的?

astaxie發表於2020-04-05

原文地址:https://medium.com/a-journey-with-go/go-how-does-gops-interact-with-the-runtime-778d7f9d7c18

本文基於 Go 1.13 和 gops 0.3.7.

gops 旨在幫助開發人員診斷 Go 流程並與之互動。它提供了跟蹤執行中的程式幾秒鐘的功能,可以通過獲取 CPU 配置檔案pprof,甚至可以直接與垃圾收集器進行互動。

發現

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 看到程式啟動以及它自己的過程。基於此輸出,我們唯一需要的是程式 ID 就可以開始與程式進行互動。但是,讓我們瞭解 gops 是如何只過濾 Go 程式。

首先,gops 列出所有過程。然後,對於每個程式,它將開啟二進位制檔案以讀取其符號表:

如果符號表包含runtime.main(主 goroutine 的入口)或main.main(我們程式的入口),則可以將其標記為 Go 程式。

有關符號表的更多資訊,建議您閱讀我的文章 “Go:如何利用符號表”。要了解有關主 goroutine 的更多資訊,建議您閱讀我的文章 “ Go:g0,Special 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 與 Go 程式之間的通訊是通過 TCP 和 Go 程式的暴露端點進行的:

分配給每個程式的埠都寫在配置檔案中,例如,path/to/config/{processID}可以很容易讓 gops 知道暴露的埠。然後,gops 可以將命令標誌傳送到代理將在其中收集資料並進行響應的程式:

更多原創文章乾貨分享,請關注公眾號
  • gops 是怎麼和 Go 的執行時進行互動的?
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章