Go: Goroutine 泄漏檢查器

Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

具有監控存活的 goroutine 數量功能的 APM (Application Performance Monitoring) 應用程序性能監控可以輕鬆查出 goroutine 泄漏。例如 NewRelic APM 中 goroutine 的監控。

見:https://docs.newrelic.com/docs/agents/go-agent/features/go-runtime-page-troubleshoot-performance-problems。

goroutine 泄漏會導致內存中存活的 goroutine 數量不斷上升,直到服務宕機爲止。因此,可以在代碼部署之前,通過一些方法來檢查程序中是否存在泄漏。

本文是 Go 語言中文網組織的 GCTT 翻譯,發佈在 Go 語言中文網公衆號,轉載請聯繫我們授權。

泄漏檢測

隸屬於 Uber 公司的 Go 團隊在 GitHub 開源了他們的 goroutine 泄漏檢測器 [1] 出來,一個與單元測試結合使用的工具。goleak 可以監控當前測試代碼中泄漏的 goroutine。下面有一個 goroutine 泄漏的例子:

func leak() error {
 go func() {
  time.Sleep(time.Minute)
 }()

 return nil
}

測試代碼:

func TestLeakFunction(t *testing.T) {
 defer goleak.VerifyNone(t)

 if err := leak(); err != nil {
  t.Fatal("error not expected")
 }
}

運行結果中展示了 goroutine 的泄漏情況:

從報錯信息中我們可以提取出兩個有用的信息:

之後,我們就可以從這些 trace 中獲取到 goroutine 的詳細執行情況。

到此,我們已經檢測到了泄漏的 goroutine,並且知道了它詳細的運行情況。現在,我們需要通過學習這個庫的運行原理來了解這種檢測方法的侷限性。

運行原理

啓用泄漏檢測的唯一要求就是在測試代碼結束之前,調用 goleak 庫來檢測泄漏的 goroutine。事實上,goleak 檢測了所有的 goroutine 而不是隻檢測泄漏的 goroutine

goleak 運行結果中首先列出了所有存在的 goroutine,以下是運行結果的完成截圖:

goroutine 的堆棧信息由 golang 標準庫中的 runtime.Stack,它可以被任何人取到。不過,Goroutine 的 ID 是拿不到的 [2]

之後,goleak 解析所有的 goroutine 出並通過以下規則過濾 go 標準庫中產生的 goroutine:

經過此次過濾後,如果沒有剩餘的 goroutine,則表示沒有發生泄漏。但是 goleak 還是存在一下缺陷:

goleak 庫雖然不是完美的,但是瞭解其侷限性和缺陷,也可以儘量避免因爲 goroutine 泄漏,而要調試在生產環境中的代碼。

有意思的是,在 net/http 庫中也使用了這個庫來檢測泄漏的 goroutine。下面是一些測試代碼中的使用 demo:

上圖中的 afterTest 中可以添加 goleak 的調用邏輯以查看 goroutine 的信息,以發現可能會出現泄漏的 goroutine。


via: https://medium.com/a-journey-with-go/go-goroutine-leak-detector-61a949beb88

作者:Vincent Blanchon[4] 譯者:CengSin[5] 校對:unknwon[6]

參考資料

[1]

goroutine 泄漏檢測器: https://github.com/uber-go/goleak

[2]

Goroutine 的 ID 是拿不到的: https://groups.google.com/forum/#!topic/golang-nuts/0HGyCOrhuuI

[3]

Go: gsignal, Master of goroutine: https://medium.com/a-journey-with-go/go-gsignal-master-of-signals-329f7ff39391

[4]

Vincent Blanchon: https://medium.com/@blanchon.vincent

[5]

CengSin: https://github.com/CengSin

[6]

unknwon: https://github.com/unknwon

[7]

GCTT: https://github.com/studygolang/GCTT

[8]

Go 中文網: https://studygolang.com/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/eSa6B1Z1cnpUJ1Vn3bxhUA