利用事务确保一致性
- 方案:在 MongoDB 4.0 及以上版本,可以使用多文档事务。对于多个写操作同时修改同一文档不同动态字段的场景,将这些操作放在一个事务中。例如:
from pymongo import MongoClient
from pymongo.errors import OperationFailure
client = MongoClient()
db = client['your_database']
with client.start_session() as session:
session.start_transaction()
try:
collection = db['your_collection']
collection.update_one({'_id': 'document_id'}, {'$set': {'field1': 'new_value1'}}, session=session)
collection.update_one({'_id': 'document_id'}, {'$set': {'field2': 'new_value2'}}, session=session)
session.commit_transaction()
except OperationFailure as e:
session.abort_transaction()
- 原理:事务保证了一组操作要么全部成功,要么全部失败。MongoDB 通过预写式日志(WAL)来记录事务操作,确保在发生故障时可以恢复到事务执行前的状态。在事务执行过程中,会对涉及的文档加锁,防止其他事务同时修改。
副本集与读偏好
- 方案:使用副本集,并设置读偏好为
primary
。这样读操作始终从主节点读取数据,能获取到最新的数据。例如,在应用程序连接字符串中设置读偏好:
client = MongoClient('mongodb://primary_host:27017,secondary_host1:27017,secondary_host2:27017/?readPreference=primary')
- 原理:副本集的主节点接收所有写操作,并将操作记录通过 oplog 同步到从节点。设置读偏好为
primary
可以确保读操作获取到最新提交的数据,因为主节点总是拥有最新的状态。
分片与一致性
- 方案:如果数据量较大使用分片集群,在进行写操作时,确保相关文档在同一分片内。可以通过合理选择分片键来实现,例如选择与业务紧密相关且能均匀分布数据的字段作为分片键。同时,利用事务来保证同一分片内多文档操作的一致性。
- 原理:分片集群将数据分布在多个分片上,每个分片是一个独立的副本集。合理的分片键选择可以避免跨分片的事务操作,因为跨分片事务相对复杂且性能较低。同一分片内的操作可以利用副本集和事务的机制保证一致性。
最终一致性实现
- 方案:对于一些对实时一致性要求不高的业务场景,可以利用 MongoDB 的最终一致性特性。从节点在同步主节点 oplog 时会有一定延迟,但最终会达到一致状态。应用程序可以在读取数据时,进行适当的重试或者使用缓存来处理可能的不一致情况。
- 原理:副本集的从节点通过异步复制主节点的 oplog 来保持数据同步。由于网络延迟等因素,从节点的数据可能会落后于主节点。但随着时间推移,从节点会不断同步,最终达到与主节点一致的状态。