可重试写入

在本页面

3.6版的新功能

可重试写入允许MongoDB驱动程序在遇到网络错误或在复制集或分片群集中找不到正常的主操作时自动重试特定的写操作一次。

前提条件

可重试写入具有以下要求:

支持的部署Topologie

​ 可重试写入需要 复制集分片群集,并且不支持独立实例。

支持的存储引擎

​ 可重试写入需要支持文档级锁定的存储引擎,例如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或更高。有关featureCompatibilityVersion标志的更多信息,请参见setFeatureCompatibilityVersion

写确认书

Write Concern0的写操作是不可重试的。

可重试写入和多文档交易

版本4.0中的新功能

事务提交和中止操作是可重试的写操作。如果提交操作或中止操作遇到错误,MongoDB驱动程序将重试操作一次,而不管retryWrites是否被设置为false

有关交易的更多信息,请参见Transactions

启用可重试写入

MongoDB驱动程序

官方的MongoDB 3.6和4.0兼容驱动程序需要在连接字符串中包含retryWrites=true选项,以启用该连接的可重试写操作。

官方的MongoDB 4.2兼容驱动程序在默认情况下启用了可重试写。升级到与4.2兼容的驱动程序,要求可重试写的应用程序可能会忽略retryWrites=true选项。升级到与4.2兼容的驱动程序,要求禁用可重试写的应用程序必须在连接字符串中包含retryWrites=false

Mongo shell

要在mongo shell中启用可重试写入,请使用--retryWrites命令行选项:

mongo --retryWrites

可重试的写操作

当发出已确认的写关注时,可以重试以下写操作; 例如,Write Concern不能为**{w:0}**。

[success] Note

事务中的写操作不能单独重试。

方法
说明

单个文档删除操作

只包含单文档写操作的批量写操作。可重试的大容量操作可以包括指定的写操作的任何组合,但不能包括任何多文档写操作,比如updateMany

仅由单文档写操作组成的批量写操作。可重试的大容量操作可以包括指定的写操作的任何组合,但不能包括任何多文档写操作,比如update,它为multi选项指定true

分片键值更新

从MongoDB 4.2开始,您可以通过发布可重试写入或事务处理中的单文档update / findAndModify操作来更新文档的分片键值(除非分片键字段是不可变的**_id**字段)。 有关详细信息,请参见更改文档的分片键值.。

  • MongoDB 4.2将重试遇到重复密钥异常的某些单文档upsert(更新使用upsert:truemulti:false)。 有关条件,请参阅 Duplicate Key Errors on Upsert .

  • 在MongoDB 4.2之前,MongoDB不会重试遇到重复键错误的upsert操作。

行为

持续的网络错误

MongoDB可重试写只做一次重试尝试。这有助于解决暂时的网络错误和复制集选举,但不能解决持久的网络错误。

故障转移期

如果驱动程序在目标复制集中或分片集群分片中找不到正常的主服务器,则驱动程序在重试之前会等待serverSelectionTimeoutMS毫秒来确定新的主服务器。可重试写操作不会处理故障转移周期超过serverSelectionTimeoutMS的实例。

[warning] Warning

如果客户端应用程序在发出写操作后的时间超过localLogicalSessionTimeoutMinutes,那么当客户端应用程序开始响应时(无需重新启动),可能会重试并再次应用写操作。

Upsert上的重复键错误

MongoDB 4.2将重试单文档的upsert操作(即:upsert: truemulti: false)由于重复的键错误而失败,只有当操作满足以下所有条件:

  • 目标集合具有导致重复键错误的唯一索引。

  • 更新匹配条件为:

    • 单个相等谓词

      { "fieldA" : "valueA" }

    • 相等谓词的逻辑

      { "fieldA" : "valueA", "fieldB" : "valueB" }

  • 唯一索引键模式中的字段集与更新查询谓词中的字段集匹配。

  • 更新操作不会修改查询谓词中的任何字段。

    下表包含服务器可以或不能在重复键错误时重试的upsert操作示例:

唯一索引键模式

更新操作

可重试

{ _id : 1 }

db.collName.updateOne( { _id : ObjectId("1aa1c1efb123f14aaa167aaa") }, { $set : { fieldA : 25 } }, { upsert : true } )

{ fieldA : 1 }

db.collName.updateOne( { fieldA : { $in : [ 25 ] } }, { $set : { fieldB : "someValue" } }, { upsert : true } )

{ fieldA:1, fieldB :1 }

db.collName.updateOne( { fieldA : 25, fieldB : "someValue" }, { $set : { fieldC : false } }, { upsert : true } )

{ fieldA : 1 }

db.collName.updateOne( { fieldA : { $lte : 25 } }, { $set : { fieldC : true } }, { upsert : true } )

没有 查询谓词fieldA不等于

{ fieldA : 1 }

db.collName.updateOne( { fieldA : { $in : [ 25 ] } }, { $set : { fieldA : 20 } }, { upsert : true } )

没有 更新操作修改查询谓词中指定的字段。

{ _id : 1 }

db.collName.updateOne( { fieldA : { $in : [ 25 ] } }, { $set : { fieldA : 20 } }, { upsert : true } )

没有 查询谓词字段集(fieldA)与索引关键字字段集()不匹配**_id**。

{ fieldA : 1 }

db.collName.updateOne( { fieldA : 25, fieldC : true }, { $set : { fieldD : false } }, { upsert : true } )

没有 这组查询谓词的字段(fieldAfieldC)不匹配组索引键的字段(fieldA

在MongoDB 4.2之前,MongoDB可重试写不支持由于重复的键错误而失败的重试更新。

诊断程序

版本3.6.3中的新功能

serverStatus命令及其mongo shell帮助程序 db.serverStatus()transactions节中包含有关可重试写入的统计信息。

针对本地数据库的可重试写入

官方的MongoDB 4.2系列驱动程序默认情况下启用重试写入。 除非明确禁止重试写入,否则写入本地数据库的应用程序在升级到4.2系列驱动程序时将遇到写入错误。

要禁用可重试写入,请在MongoDB集群的连接字符串中指定retryWrites=false

译者:杨帅

校对:杨帅

最后更新于