大家好,我是煎鱼。
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