【发布时间】:2017-04-03 14:14:04
【问题描述】:
我想知道 Go 中使用 mgo 的 MongoDB 会话管理,尤其是关于如何正确确保会话关闭以及如何对写入失败做出反应。
我已阅读以下内容:
Best practice to maintain a mgo session
Should I copy session for each operation in mgo?
仍然无法将其应用于我的情况。
我有两个 goroutine 将一个又一个事件存储到 MongoDB 中,共享同一个 *mgo.Session,两者看起来都像下面这样:
func storeEvents(session *mgo.Session) {
session_copy := session.Copy()
// *** is it correct to defer the session close here? <-----
defer session_copy.Close()
col := session_copy.DB("DB_NAME").C("COLLECTION_NAME")
for {
event := GetEvent()
err := col.Insert(&event)
if err != nil {
// *** insert FAILED - how to react properly? <-----
session_copy = session.Copy()
defer session_copy.Close()
}
}
}
col.Insert(&event) 几个小时后返回错误
read tcp 127.0.0.1:46954->127.0.0.1:27017: i/o timeout
我不确定如何对此做出反应。发生此错误后,它会发生在所有后续写入中,因此似乎我必须创建一个新会话。对我来说似乎有替代方案:
1) 重启整个 goroutine,即
if err != nil {
go storeEvents(session)
return
}
2) 创建一个新的会话副本
if err != nil {
session_copy = session.Copy()
defer session_copy.Close()
col := session_copy.DB("DB_NAME").C("COLLECTION_NAME")
continue
}
--> 我如何使用defer session_copy.Close() 是否正确? (注意上面的 defer 引用了另一个会话的 Close() 函数。无论如何,这些会话永远不会关闭,因为该函数永远不会返回。也就是说,随着时间的推移,许多会话将被创建而不是关闭。
其他选项?
【问题讨论】:
-
你应该看看这里blog.golang.org/defer-panic-and-recover.. 基本上如果 err != nil 你应该恐慌 err,然后通过恢复来捕获它,创建会话的副本并将该副本推迟到会议。您已经使用延迟正确关闭了连接。但是,如果您在插入时抛出错误,您还应该调查原因,而不是依赖尝试重新插入。我已经使用 mgo 完成了数百万次插入,并且从未抛出错误。事实上,我遇到的大多数 Mongo 错误都与 Mongo 本身有关,而不是驱动程序。
-
@reticentroot 感谢有关延迟的信息;关于插入错误背后的原因:你有什么建议去哪里看吗?我已经搜索了错误信息,在stackoverflow上找到了帖子,表明这是因为超时;对我来说,超时似乎不太可能,因为a)插入相当小,并且b)一旦发生错误,它会在每个后续插入中重新发生;尽管如此,我还是编写了代码来测量插入时间并记录它以防返回错误,但从那时起(昨天),还没有再次发生此类错误
-
检查你的 mongod 实例。如果您打开更多连接然后您的实例可以处理,它可能会超时。您可以将错误添加到您的帖子中吗?
-
@reticentroot mongodb 日志中没有错误;只有许多“已接受连接”,然后是“结束连接”日志条目(时间戳仅间隔 10 毫秒);对于失败的插入,没有提到插入 - 通常,对于插入,日志有一个条目“插入
. 查询: ” -
实际上,在发生错误的原始设置中,我直接从两个不同的 goroutine 使用会话指针,而没有在每个 goroutine 中创建副本;现在,由于我在 storeEvents() 函数中更改为上面显示的代码,因此尚未出现错误;我会等到星期一,看看工作日会发生什么,还有更多活动