使用mgo驱动连接MongoDB副本集时OP_GET_MORE报错求助
问题原因分析
这个错误的本质是旧驱动协议与MongoDB集群配置的冲突:
- 你使用的mgo驱动属于较老的MongoDB驱动,它处理游标分页(比如聚合查询返回大量数据时的
getMore操作)时,用的是MongoDB旧的OP_GET_MORE网络协议操作码。 - 当你给集群设置了自定义默认写关注(
w:"majority")后,MongoDB会要求所有游标相关的后续操作必须使用命令式的getMore命令,不允许用旧的OP_GET_MORE操作——因为旧操作无法传递自定义写关注的上下文,而集群默认写关注会绑定到游标上,触发校验失败。 - 把默认写关注设为
{}时,相当于用MongoDB原生默认写关注(w:1),这时MongoDB允许旧的OP_GET_MORE操作,错误也就消失了。
另外提一句:你连接代码里连续调用了两次SetMode,mgo.SecondaryPreferred会覆盖前面的mgo.Monotonic,这行是多余的,可以删掉。
解决方案
方案1:针对读操作会话重置写关注
聚合属于读操作,不需要继承会话的写关注配置。你可以在创建会话副本后,显式重置写关注为默认,避免读操作带上majority写关注:
sessionCopy := mongoSession.Copy() defer sessionCopy.Close() // 重置写关注为默认,解决游标操作的协议冲突 sessionCopy.SetSafe(nil) getCollection := sessionCopy.DB(MerchantDb.Database).C(config.BookingsCollection) // 后续聚合代码不变
方案2:升级到官方MongoDB Go驱动
mgo已经停止维护多年,官方的mongodb-go-driver完全支持MongoDB最新协议,会自动使用命令式的getMore操作,从根源上避免这类协议兼容问题。
方案3:调整写关注的配置方式
如果业务需要写操作默认使用majority写关注,不要在集群层面设置defaultWriteConcern,而是只在写操作的会话中显式设置写关注,读操作的会话不设置:
- 集群层面恢复默认写关注:
db.adminCommand({ setDefaultRWConcern: 1, defaultReadConcern: { level : "majority" }, defaultWriteConcern: {} })
- 在执行写操作的代码中,单独设置写关注:
// 写操作会话 writeSession := mongoSession.Copy() defer writeSession.Close() writeSession.SetSafe(&mgo.Safe{WMode: "majority"}) // 执行插入、更新等写操作
内容的提问来源于stack exchange,提问作者Rohit
相关产品推荐
相关产品推荐

