交易次数 > 生产注意事项
在本页面
下一页列出了运行事务的一些生产注意事项。无论您在副本集或分片群集上运行事务,这些规则均适用。有关在分片群集上运行事务的信息,另请参见生产注意事项(共享群集),以获取特定于分片群集的其他注意事项。
在版本4.0中,MongoDB支持副本集上的多文档事务。
在4.2版中,MongoDB引入了分布式事务,它增加了对分片群集上多文档事务的支持,并合并了对副本集上多文档事务的现有支持。
要在MongoDB 4.2部署(副本集和分片群集)上使用事务,客户端必须使用针对MongoDB 4.2更新的MongoDB驱动程序。
分布式事务和多文档事务
从MongoDB 4.2开始,这两个术语是同义词。分布式事务是指分片群集和副本集上的多文档事务。从MongoDB 4.2开始,多文档事务(无论是在分片群集或副本集上)也称为分布式事务。
要使用事务, 部署的所有成员的featureCompatibilityVersion必须至少为:
部署方式 | 最低要求 featureCompatibilityVersion |
---|---|
副本集 | 4.0 |
分片集群 | 4.2 |
要检查成员的fCV,请连接到该成员并运行以下命令:
有关更多信息,请参见
setFeatureCompatibilityVersion
参考页。
默认情况下,事务的运行时必须少于一分钟。您可以transactionLifetimeLimitSeconds
为
mongod
实例修改此限制
。对于分片群集,必须为所有分片副本集成员修改参数。超过此限制的事务将被视为已过期,并且将通过定期清除过程中止。
对于分片群集,您还可以maxTimeMS
在上指定一个限制
commitTransaction
。有关更多信息,请参阅分片群集事务时间限制。
为防止存储缓存压力对性能造成负面影响:
这transactionLifetimeLimitSeconds
还确保了过期的事务会定期中止,以减轻存储缓存的压力。
您不能在具有writeConcernMajorityJournalDefault
设置为的分片的分片群集上运行事务false
(例如,具有使用内存存储引擎的投票成员的分片)。
对于具有主次仲裁器(PSA)体系结构的三成员副本集或具有三成员PSA分片的分片群集,您可能已禁用了“读取多数”以避免担心缓存压力。
如果事务涉及已禁用读关注度“多数”的分片,则不能"snapshot"
对事务使用读关注度。您只能使用已读关注"local"
或
"majority"
用于事务。如果使用读取关注"snapshot"
,则事务错误并中止。
如果任何事务的读或写操作涉及禁用了读取关注的分片,则其写操作跨越多个分片的事务将出错并中止
"majority"
。
您可以指定读取关注点"local"
,
"majority"
或者"snapshot"
甚至在副本集中已禁用读取关注点“多数”。
但是,如果您打算过渡到具有禁用读关注多数分片的分片群集,则可能希望避免使用读关注"snapshot"
。
小费
要检查是否已禁用阅读关注“多数”,您可以db.serverStatus()
在mongod
实例上运行
并检查该storageEngine.supportsCommittedReads
字段。如果为false
,则禁用“大多数”关注。
默认情况下,事务等待长达5
毫秒,以获取事务中的操作所需的锁。如果事务无法在5
毫秒内获得其所需的锁,则事务中止。
事务在中止或提交时释放所有锁。
小费
在紧接开始事务之前创建或删除集合时,如果在事务内访问了该集合,则发出具有写关注的create或drop操作,"majority"
以确保该事务可以获取所需的锁。
您可以使用该maxTransactionLockRequestTimeoutMillis
参数来调整事务等待获取锁的时间。增加maxTransactionLockRequestTimeoutMillis
允许事务中的操作等待指定的时间来获取所需的锁。这可以避免在瞬时并发锁定获取时避免事务中止,例如快速运行的元数据操作。但是,这可能会延迟中止死锁的事务操作。
您还可以通过设置maxTransactionLockRequestTimeoutMillis
为来使用特定于操作的超时
-1
。
如果正在进行多文档事务,则影响相同数据库或集合的新DDL操作将在事务后面等待。尽管存在这些未决DDL操作,但是与未决DDL操作访问相同数据库或集合的新事务无法获取所需的锁,并且将在等待后中止maxTransactionLockRequestTimeoutMillis
。另外,访问相同数据库或集合的新的非事务操作将阻塞,直到达到maxTimeMS
极限为止
。
请考虑以下情形:
在进行中的事务正在数据库中的employees
集合上执行各种CRUD操作的同时hr
,管理员db.collection.createIndex()
对employees
集合发出DDL操作。
createIndex()
需要对集合使用排他的集合锁。
在进行中的事务完成之前,该
createIndex()
操作必须等待获取锁。任何影响employees
收集并在createIndex()
挂起时启动的新事务都必须等到createIndex()
完成后再进行
。
待处理的createIndex()
DDL操作不会影响hr
数据库中其他集合上的事务。例如,数据库中contractors
集合上的新事务hr
可以正常启动和完成。
在进行中的事务employees
对hr
数据库中的集合执行各种CRUD操作时,管理员collMod
对contractors
同一数据库中的集合执行DDL操作。
collMod
需要对父hr
数据库进行数据库锁定。
在进行中的事务完成之前,该collMod
操作必须等待获取锁。任何影响hr
数据库或其任何集合并在collMod
挂起时启动的新事务都必须等到collMod
完成之后再进行
。
在这两种情况下,如果DDL操作的未决状态超过
maxTransactionLockRequestTimeoutMillis
,则在该操作之后等待的未决事务将中止。也就是说,的值
maxTransactionLockRequestTimeoutMillis
必须至少涵盖进行中的事务和挂起的DDL操作完成所需的时间。
如果事务正在进行中,并且在事务外部进行写操作会修改文档,而该文件后来在事务中尝试修改,则事务会由于写冲突而中止。
如果事务正在进行中并且已锁定修改文档,则在事务外部进行写尝试修改同一文档时,该写操作将一直等到事务结束。
也可以看看
事务内的读取操作可以返回陈旧的数据。也就是说,不能保证事务内的读取操作会看到其他已提交事务执行的写操作或非事务性写操作。例如,请考虑以下顺序:1)正在进行事务; 2)在事务外部进行写入会删除文档; 3)事务内部的读取操作能够读取已删除的文档,因为该操作使用快照从写之前开始。
为避免对单个文档进行过时的内部事务读取,可以使用该db.collection.findOneAndUpdate()
方法。例如:
块迁移在某些阶段获得排他的收集锁。
如果正在进行的事务锁定了集合,并且涉及该集合的块迁移开始,则这些迁移阶段必须等待事务释放对集合的锁定,从而影响块迁移的性能。
如果大块迁移与事务交织(例如,如果在大块迁移已在进行的同时启动事务,并且迁移在事务锁定集合之前完成),则提交期间的事务错误并中止。
根据两个操作的交错方式,包括一些示例错误(错误消息已被缩写):
an error from cluster data placement change ... migration commit in progress for <namespace>
Cannot find shardId the chunk belonged to at cluster time ...
在提交事务期间,外部读取操作可能会尝试读取将由事务修改的相同文档。如果事务写入多个分片,则在尝试进行分片提交时
snapshot
或
"linearizable"
或属于因果一致会话(即,包括afterClusterTime)的外部读取等待事务的所有写入均可见。要在MongoDB 4.2部署(副本集和分片群集)上使用事务,客户端必须使用针对MongoDB 4.2更新的MongoDB驱动程序。
在具有多个mongos
实例的分片群集上,使用针对MongoDB 4.0(而非MongoDB 4.2)更新的驱动程序执行事务将失败,并可能导致错误,包括:
注意
您的驱动程序可能会返回其他错误。有关详细信息,请参阅驱动程序的文档。
错误代码 | 错误信息 |
---|---|
251 | cannot continue txnId -1 for session ... with txnId 1 |
50940 | cannot commit with no participants |
也可以看看