🚀 优质资源分享 🚀
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
💛Python量化交易实战💛 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
背景
用metux lock for循环,在for循环中又 向带缓冲的Channel 写数据时,千万要小心死锁!
最近,我在测试ws长链接网关,平均一个星期会遇到一次服务假死问题,因为并不是所有routine被阻塞,故runtime的检查无法触发,http health check又是另开的一个端口,k8s检查不到异常,无法重启服务。
经过一番排查论证之后,确定了是 **混用带缓冲的Channel和Metux造成的死锁 (具体在文末总结)**问题,请看下面详细介绍。
死锁现象
我们使用了gin框架,预先接入了pprof封装组件,这样通过http(非生产)就能很方便的查看go runtime的一些信息。
果不其然,我们打开后发现了大量的 goroutine泄漏:
点开 full goroutiine stack dump,可以看到有很多死锁等待,导致goroutine被阻塞:
其中:
- semacquire阻塞:有9261/2 个 routine
- chan send阻塞:有9处
问题出在哪里?
启发
有一个作者:https://wavded.com/post/golang-deadlockish/ 分享了一个类似的问题。
下面是引用的部分正文内容。
1)Wait your turn
在我们为应用程序提供的一项支持服务中,每个组都有自己的Room,可以这么说。我们在向房间广播消息之前锁定了members列表,以避免任何数据竞争或可能的崩溃。像这样:
| 123456789 | func
(r *Room) Broadcast(msg string) {``r.membersMx.RLock()``defer
r.membersMx.RUnlock()``for
_, m :=
range
r.members {``if
err := s.Send(msg); err != nil {