好物分享:快速找到 Goroutine 泄露的地方
大家好,我是煎魚。
Go 語言能夠廣受大家喜歡,其中一個原因就是他的協(xié)程做的非常非常簡單,初學(xué)的入門者都可以使用。

平時只需 go 關(guān)鍵字一下,成千上萬個 goroutines 就出現(xiàn)了:
for?...
??go?func(){}
起協(xié)程就跟下餃子的。這時就個大問題,因為協(xié)程用起來簡單,出問題出起來也很快。
也就是常常會出現(xiàn) goroutine 泄露,查起來很費(fèi)勁。
goleak
今天給大家推薦一個好物,定位為純介紹。他來自 Uber 的 Goroutine leak detector[1],他能夠結(jié)合單元測試去快速的檢測 goroutine 泄露,達(dá)到避免和排查的目的。

在命令行執(zhí)行第三方庫安裝:
go?get?-u?go.uber.org/goleak
channel 會一直阻塞,導(dǎo)致泄露的方法:
func?leak()?{
?ch?:=?make(chan?struct{})
?go?func()?{
??ch?<-?struct{}{}
?}()
}
如果我們直接在常規(guī)的測試方法中調(diào)用:
func?TestLeak(t?*testing.T)?{
?leak()
}
輸出結(jié)果:
===?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()
}
再進(jìn)行驗證:
===?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
可以從報告中看到,運(yùn)行結(jié)構(gòu)會明確的告訴你發(fā)現(xiàn)泄露的 goroutine 的代碼堆棧和泄露類型,非常的省心。
另外在內(nèi)部的 CI/CD 流程里,把 goleak 結(jié)合上,對于平時的 CR 也是一個不錯的輔助。
總結(jié)
今天我們的好物分享介紹了一個小工具,能夠解決大家團(tuán)隊中時長遇到的 goroutine 泄露問題,除了本文提到的 uber-go/goleak,也還有 ysmood/gotrace 等同類型的庫能夠達(dá)到類似的效果。
希望對你排查 goroutine 泄露有所幫助:)
參考資料
Goroutine leak detector: github.com/uber-go/goleak
關(guān)注煎魚,獲取業(yè)內(nèi)第一手消息和知識 ??

你好,我是煎魚,出版過 Go 暢銷書《Go 語言編程之旅》,再到獲得 GOP(Go 領(lǐng)域最有觀點(diǎn)專家)榮譽(yù),點(diǎn)擊藍(lán)字查看我的出書之路。
日常分享高質(zhì)量文章,輸出 Go 面試、工作經(jīng)驗、架構(gòu)設(shè)計,加微信拉讀者交流群,和大家交流!
