可重试写入 (Retryable Writes)
可重试写入允许 MongoDB 驱动程序在遇到网络错误,或者在副本集或分片集群中找不到健康的 主节点时,自动重试某些写入操作。
先决条件
可重试写入具有以下要求:
- 支持的部署拓扑结构
- 可重试写入需要副本集或分片集群,并且不支持独立实例。
- 支持的存储引擎
- 可重试写入需要支持文档级锁定的存储引擎,例如 WiredTiger 或 内存存储引擎。
- 3.6+ MongoDB 驱动程序
客户端需要针对 MongoDB 3.6 或更高版本更新 MongoDB 驱动程序:
Java 3.6 +
Python 3.6+
C 1.9+
Go 1.8+
C# 2.5 +
节点3.0 +
Ruby 2.5+
Rust 2.1+
Swift 1.2 +
Perl 2.0 +
PHPC 1.4 +
Scala 2.2+
C++ 3.6.6 +
- MongoDB 版本
- 集群中每个节点的 MongoDB 版本必须为
3.6
或更高版本,并且集群中每个节点的featureCompatibilityVersion
必须为3.6
或更高版本。有关featureCompatibilityVersion
标志的详细信息,请参阅setFeatureCompatibilityVersion
。 - 写确认
- 写关注为
0
时发出的写入操作不可重试。
可重试写入和多文档事务
事务提交和中止操作是可重试的写入操作。如果提交操作或中止操作遇到错误,则不管 retryWrites
是否设置为 false
,MongoDB 驱动程序都会重试该操作一次。
事务中的写入操作不可单独重试,无论 retryWrites
的值如何。
有关事务的更多信息,请参阅事务。
启用可重试写入
- MongoDB 驱动程序
- 与 MongoDB 4.2及更高版本兼容的驱动程序默认启用可重试写入。 早期的驱动程序需要
retryWrites=true
选项。 在使用与 MongoDB 4兼容的驱动程序的应用程序中,可以省略retryWrites=true
选项。 2及更高版本。要禁用可重试写入功能,使用与 MongoDB 4.2 及更高版本兼容的驱动程序的应用程序必须在连接字符串中包含retryWrites=false
。 mongosh
可重试写入默认在
mongosh
中启用。要禁用可重试写入,请使用--retryWrites=false
命令行选项:mongosh --retryWrites=false
可重试写入操作
当以确认写发出时,以下写入操作是可重试的;例如,写关注不能为 {w: 0}
。
注意
事务中的写入操作不可单独重试。
方法 | 描述 |
---|---|
插入操作 | |
单个文档更新操作 | |
单个文档删除操作 | |
findAndModify 运营。所有 findAndModify 操作都是单文档操作。 | |
仅单文档写入操作的批量写入操作。可重试的批量操作可以包括指定写入操作的任意组合,但包括任何多文档写入操作,例如 updateMany 。 | |
批量写入操作只包括单文档写入操作。可重试批量操作可以包括指定写入操作的任意组合,但不能包括任何多文档写入操作,例如为 multi 选项指定 true 的 update 。 |
行为
持续性网络错误
MongoDB 可重试写入仅进行一次重试尝试。这有助于解决暂时性网络错误和副本集选举,但不能解决持续性网络错误。
故障转移周期
如果驱动程序在目标副本集或分片集群分片中找不到正常的主节点,则驱动程序将等待 serverSelectionTimeoutMS
毫秒,以确定新的主节点,然后再重试。可重试写入不处理故障转移周期超过 serverSelectionTimeoutMS
的实例。
警告
如果客户端应用程序在发出写入操作后暂时无响应的时间超过 localLogicalSessionTimeoutMinutes
,则当客户端应用程序开始响应(无需重启)时,可能会重试并再次应用写入操作。
诊断
serverStatus
命令及其 mongosh
Shell 助手 db.serverStatus()
在 transactions
部分中包含有关可重试写入的统计信息。
针对 local
数据库的可重试写入
默认情况下,官方 MongoDB 驱动程序启用可重试写入。除非显式禁用可重试写入,否则,写入 local
数据库的应用程序会遇到写入错误。
要禁用可重试写入,请在 MongoDB 集群连接字符串中指定 retryWrites=false
。
Error Handling
从 MongoDB 6.1 开始,如果可重试写入的第一次和第二次尝试都失败而没有执行单独的写入,则 MongoDB 将返回带有NoWritesPerformed
标签的错误。
NoWritesPerformed
标签区分 insertMany()
等批量操作的结果。在insertMany
操作中,可能会出现以下结果:
结果: | MongoDB 输出 |
---|---|
未插入任何文档。 | 返回错误但不带 NoWritesPerformed 标签。 |
部分工作已完成。(至少插入一个文档,但不是全部。) | 返回错误但不带 NoWritesPerformed 标签。 |
所有文档均已插入。 | 成功返回。 |
应用程序可以使用 NoWritesPerformed
标签来明确确定没有插入任何文档。。此错误报告使应用程序可以在处理可重试写入时保持数据库的准确状态
在 MongoDB 的早期版本中,当第一次和第二次可重试写入操作失败时,将会返回错误。但是,指明未执行任何写入操作时没有区别。