目录
进入MongoDB中文手册(4.2版本)目录
可重试写入为3.6版的新功能。
可重试写入允许MongoDB驱动程序在遇到网络错误或在 副本集或 分片群集中的主节点( primary)异常时,自动重试一次某些写入操作。
1 前提条件
可重试写入具有以下要求:
- 支持的拓扑部署
可重试的写入需要副本集 或分片群集,不支持单实例。 - 支持的存储引擎
可重试写入需要支持文档级锁定的存储引擎,例如WiredTiger或 内存中的存储引擎。 - 3.6+ MongoDB驱动程序
客户端需要为MongoDB 3.6或更高版本更新的MongoDB驱动程序:- Java 3.6+
- Python 3.6+
- C 1.9+
- C# 2.5+
- Node 3.0+
- Ruby 2.5+
- Perl 2.0+
- PHPC 1.4+
- Scala 2.2+
- MongoDB版本
集群中每个节点的MongoDB版本必须大于或等于3.6,集群中每个节点的featureCompatibilityVersion值必须大于或等于3.6。有关setFeatureCompatibilityVersion更多信息,请参见 featureCompatibilityVersion。 - 写确认
写策略设置为0的写操作不重试。
2 重试写入和多文档事务
版本4.0中的新功能。
事务提交和中止操作( transaction commit and abort operations) 是重试写入操作。如果提交操作或中止操作遇到错误,无论是否将retryWrites设置为 false,MongoDB驱动程序都将重试一次该操作。
事务的写操作不可单独重试,而不管retryWrites值是多少。
有关事务的更多信息,请参见事务(Transactions)。
3 启用可重试写入
3.1 MongoDB驱动程序
需要与MongoDB 3.6和4.0兼容的官方驱动程序,并且在连接字符串( connection string)中包括选项retryWrites=true,才能为该连接启用可重试的写入。
与MongoDB 4.2兼容的官方驱动程序默认情况下启用可重试写入。升级到与4.2兼容的驱动程序的应用程序可以忽略retryWrites=true 选项。应用升级到需要的4.2兼容的驱动程序 禁用重试写操作,必须在连接字符串中包括 retryWrites=false。
3.2 mongo shell
要在mongo shell中启用可重试写入,请使用–retryWrites命令行选项:
mongo --retryWrites
4 可重试的写操作
当发出已确认的写入问题时,以下写入操作可以重试;例如,写关注点 不能为。{w: 0}
以下写入操作在设置写策略确认(acknowledged write concern)时是可重试的;例如,写策略(Write Concern)不能为{w: 0}。
注意
事务内的写操作不能单独重试。
方法 | 描述 |
---|---|
db.collection.insertOne() db.collection.insert() db.collection.insertMany() | 插入操作 |
db.collection.updateOne() db.collection.replaceOne() db.collection.save() db.collection.update()这里multi设置为false | 单文档更新操作 |
db.collection.deleteOne() db.collection.remove()这里justOne设置为true | 单个文档删除操作 |
db.collection.findAndModify() db.collection.findOneAndDelete() db.collection.findOneAndReplace() db.collection.findOneAndUpdate() | findAndModify操作。所有findAndModify操作都是单文档操作。 |
db.collection.bulkWrite() 具有以下写操作: insertOne; updateOne replaceOne deleteOne | 仅由单文档写操作组成的批量写操作。可重试的批量操作可以包括指定写操作的任何组合,但不能包括任何多文档写操作,例如updateMany。 |
Bulk 操作: Bulk.find.removeOne() Bulk.find.replaceOne() Bulk.find.replaceOne() | 仅由单文档写操作组成的批量写操作。可重试批量操作可以包括指定的写操作的任何组合,但可以不包括任何多文档写操作,如multi选项设置为true的update。 |
分片键值更新
从MongoDB 4.2开始,您可以通过以可重试写入或事务方式提供单文档update或 findAndModify操作来更新文档的分片键值(除非分片键字段是不可变的_id字段)。有关详细信息,请参见更改文档的分片键值。
注意
遇到重复健值异常的某些单文档时,MongoDB 4.2将重试upsert(使用upsert: true和multi: false更新)操作。请参阅Upsert上的重复键错误。
在MongoDB 4.2之前,MongoDB不会重试遇到重复键错误的upsert操作。
5 行为
5.1 持久性网络错误
MongoDB可重试写入仅进行一次重试尝试。这有助于解决瞬态网络错误和副本集选择(replica set elections),但不能解决持久性网络错误。
5.2 故障转移期间(Failover Period)
如果驱动程序在目标副本集或分片的群集分片中找不到正常的主节点( primary),则驱动程序将等待serverSelectionTimeoutMS毫秒,然后重试,serverSelectionTimeoutMS为确定新的主节点时长。可重试的写操作不能定位到解决故障转移时间超过serverSelectionTimeoutMS毫秒的实例。
警告
如果客户端应用程序发出写操作后暂时没有响应,且没有响应的时间比localLogicalSessionTimeoutMinutes更长,则有可能当客户端应用程序开始响应(不重新启动)时,可以重试并再次发起写操作。
5.3 Upsert的重复键错误
仅当操作满足以下所有条件时,MongoDB 4.2才会重试由于重复键错误而失败的单文档upsert操作(即upsert : true和multi : false):
- 目标集合具有导致重复键错误的唯一索引;
- 更新匹配条件为:
- 单个相等语句
{ “fieldA” : “valueA” } - 或者逻辑与(AND)的相等语句
{ “fieldA” : “valueA”, “fieldB” : “valueB” }
- 单个相等语句
- 唯一索引键模式中的字段集与更新查询语句中的字段集匹配;
- 更新操作不会修改查询语句中的任何字段。
下表包含服务器可以或不能在重复键错误时重试的upsert操作示例:
唯一索引键模式 | 更新操作 | 可重试 |
---|---|---|
{ _id : 1 } | db.collName.updateOne( { _id : ObjectId(“1aa1c1efb123f14aaa167aaa”) }, { $set : { fieldA : 25 } }, { upsert : true } ) | Yes |
{ fieldA : 1 } | db.collName.updateOne( { fieldA : { $in : [ 25 ] } }, { $set : { fieldB : “someValue” } }, { upsert : true } ) | Yes |
{fieldA : 1,fieldB : 1} | db.collName.updateOne( { fieldA : 25, fieldB : “someValue” }, { $set : { fieldC : false } }, { upsert : true } ) | Yes |
{ fieldA : 1 } | db.collName.updateOne( { fieldA : { $lte : 25 } }, { $set : { fieldC : true } }, { upsert : true } ) | No 查询语句中fieldA 不是相等语句 |
{ fieldA : 1 } | db.collName.updateOne( { fieldA : { $in : [ 25 ] } }, { $set : { fieldA : 20 } }, { upsert : true } ) | No 更新操作修改了查询语句中的字段。 |
{ _id : 1 } | db.collName.updateOne( { fieldA : { $in : [ 25 ] } }, { $set : { fieldA : 20 } }, { upsert : true } ) | No 查询语句中的字段(fieldA)不匹配索引健字段(_id) |
{ fieldA : 1 } | db.collName.updateOne( { fieldA : 25, fieldC : true }, { $set : { fieldD : false } }, { upsert : true } ) | No 查询语句中的字段(fieldA,fieldC)不匹配索引健字段(fieldA) |
在MongoDB 4.2之前,MongoDB不支持由于重复的键错误而导致失败的upsert操作进行重试写入。
5.4 诊断
版本3.6.3中的新功能。
serverStatus命令及其mongo shell帮助器db.serverStatus(),包含事务中重试写入的统计信息。
5.5 本都数据库的重试写入
官方的MongoDB 4.2系列驱动程序默认情况下启用重试写入。除非明确禁止重试写入,在升级到4.2系列驱动程序后,写入本地数据库的应用程序将遇到写入错误。
要禁用可重试写入,请在MongoDB集群的连接字符串中设置retryWrites=false 。