Golang Go语言中使用mgo并发操作导致死锁

发布于 1周前 作者 eggper 来自 Go语言

go 语言的 mongodb drive mgo 不是说线程安全的么?多个协成一并发一下就死锁了啊,有人用过这个么?
Golang Go语言中使用mgo并发操作导致死锁

23 回复

上代码

更多关于Golang Go语言中使用mgo并发操作导致死锁的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


测试了你的代码,确实跑不顺畅,到后面是每 60 秒输出一条。不知道 60 秒是什么梗

我测试没有任何问题

就是这个问题,好奇怪啊,看了一天也没看出是什么问题…

一样的?要同时发起数万查询才会出这个问题,似乎

更新 1 :
加了-race 参数就能顺利跑完
go run -race test_mgo.go

更新 2 :
60 秒应该是 socket 超时,设置 session.SetSocketTimeout(35*time.Second) ,就会变成每 35 秒输出一条

感觉确实是 mgo 的问题,建议楼主去 github 提 issue

这个应该跟用的 mongodb 的配置有关,我这边反正一点问题都没有,顺利跑完, mongodb 是 ubuntu apt-get 装的 v2.6.10

ulimit -a 看看改过没有?

嗯,再测测看看

和这个没关系吧,整个只打开了一个链接…

可能是 setMode 造成的,只有 Monotonic 是 session 线程安全的,对没个 go 你试试用 session.Clone() Close()方法试试?

直接
for(){go foo()}
效率还是很低的,一方面是系统资源的申请还有 fd 的限制
第二就是资源回收。

建议用 chan 做队列和配合 select 效果应该很好

不要一直用一个 *mgo.Session ,尽量 Clone 新的 来用

少了两个关键之,密集申请和密集回收

用 go 起新的协程也需要占用 fd ,能详细解释一下么?

那么这样岂不要不断的关闭连接打开新连接了,如果有副本集的话,还有不断更新集群信息,这样效率太低了吧

mgo 的 Copy 是从连接池中取,不是重新创建的。

哦,是 clone ,看错 close 了,为什么要这么设计,好怪啊。。

昨晚试过在 for 循环里面 clone ,然后在 test()里面调 close ,结果还是不行
for i := 0; i < 100001; i++ {
go test(session.Clone(), i)
}

刚刚又试了一下把 clone 也放到 test()里面,就顺利跑完了。
看来 clone 需要在使用的 goroutine 里面调才有效

根据我的理解这个不是死锁,是卡住了。 mgo.Session 会起一个协程运行 readLoop() 读取数据,这里面会有很多锁,也就是当你开的协程少(具体看机器配置)时是没有什么问题的。 一旦你把协程数提高比如你代码里面的 10w 时, readLoop() 协程能分配到的计算资源有限,所以就会出现卡住或缓慢得到查询请求的情况。 你可以把协程数降低,单个协程的查询数提高,查询速度就会变快。 同理 copy 多个 mgo.Session 就会有启多个 readLoop() 协程 ,每个查询在对应的 readLoop ,执行回调就不会卡住了。

https://github.com/go-mgo/mgo/pull/572

居然这么久了这个问题还在,那么我来更新下解决方案吧。

在Golang中使用mgo(MongoDB官方Go驱动的早期版本)进行并发操作时遇到死锁问题,通常是由于mgo的session管理不当导致的。以下是一些可能的解决方案和建议:

  1. Session管理:确保每个goroutine使用独立的session副本或通过session的Copy方法创建新的session。mgo的session不是线程安全的,因此在并发环境下,每个操作应该使用自己的session实例。

  2. 设置PoolSize:通过mgo.SetPoolSize(n)设置session池的最大大小,确保有足够的session可供并发操作使用。这有助于减少因session不足而导致的阻塞和潜在死锁。

  3. 使用Safe模式:在进行写操作时,确保使用session.Safe()或设置更高的写关注级别,这有助于在出现问题时捕获并处理错误,从而避免死锁。

  4. 升级驱动:如果可能,考虑升级到mgo的更新版本或切换到官方推荐的MongoDB Go驱动(如go.mongodb.org/mongo-driver/mongo),这些驱动可能包含对并发操作的更好支持。

  5. 调试和监控:使用Go的并发调试工具(如race检测器)和MongoDB的监控工具来诊断死锁原因。这些工具可以帮助你识别竞争条件和资源争用。

总之,处理mgo并发操作中的死锁问题通常需要仔细管理session生命周期、合理配置session池以及使用最新的驱动库。在设计和实现并发应用时,务必考虑这些最佳实践。

回到顶部