好物分享:快速找到 Goroutine 泄露的地方

大家好,我是煎魚。

Go 語言能夠廣受大家喜歡,其中一個原因就是他的協程做的非常非常簡單,初學的入門者都可以使用。

平時只需 go 關鍵字一下,成千上萬個 goroutines 就出現了:

for ...
  go func(){}

起協程就跟下餃子的。這時就個大問題,因爲協程用起來簡單,出問題出起來也很快。

也就是常常會出現 goroutine 泄露,查起來很費勁。

goleak

今天給大家推薦一個好物,定位爲純介紹。他來自 Uber 的 Goroutine leak detector[1],他能夠結合單元測試去快速的檢測 goroutine 泄露,達到避免和排查的目的。

在命令行執行第三方庫安裝:

go get -u go.uber.org/goleak

channel 會一直阻塞,導致泄露的方法:

func leak() {
 ch := make(chan struct{})
 go func() {
  ch <- struct{}{}
 }()
}

如果我們直接在常規的測試方法中調用:

func TestLeak(t *testing.T) {
 leak()
}

輸出結果:

=== RUN   TestLeak
--- PASS: TestLeak (0.00s)
PASS

是不會有任何變化的,正常通過測試。

這時候我們需要在代碼中添加 goleak.VerifyNone 方法,如下:

import (
 "testing"
 "go.uber.org/goleak"
)

func TestLeak(t *testing.T) {
 defer goleak.VerifyNone(t)
 leak()
}

再進行驗證:

=== RUN   TestLeak
    leaks.go:78: found unexpected goroutines:
        [Goroutine 7 in state chan send, with github.com/eddycjy/awesome-project/tools.leak.func1 on top of the stack:
        goroutine 7 [chan send]:
        github.com/eddycjy/awesome-project/tools.leak.func1(0xc0000562a0)
         /Users/eddycjy/go-application/awesomeProject/tools/leak.go:6 +0x35
        created by github.com/eddycjy/awesome-project/tools.leak
         /Users/eddycjy/go-application/awesomeProject/tools/leak.go:5 +0x4e
        ]
--- FAIL: TestLeak (0.46s)
FAIL

可以從報告中看到,運行結構會明確的告訴你發現泄露的 goroutine 的代碼堆棧和泄露類型,非常的省心。

另外在內部的 CI/CD 流程裏,把 goleak 結合上,對於平時的 CR 也是一個不錯的輔助。

總結

今天我們的好物分享介紹了一個小工具,能夠解決大家團隊中時長遇到的 goroutine 泄露問題,除了本文提到的 uber-go/goleak,也還有 ysmood/gotrace 等同類型的庫能夠達到類似的效果。

希望對你排查 goroutine 泄露有所幫助:)

參考資料

[1]

Goroutine leak detector: github.com/uber-go/goleak

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