因果一致性要解决的问题(Causal Consistency and Read and Write Concerns)?
借助MongoDB的因果一致性客户端会话,读写问题的不同组合可提供不同的 因果一致性保证。如果定义因果一致性以表示耐久性,则下表列出了各种组合提供的特定保证:
阅读关注 | 写关注 | 阅读自己的文章 | 单调读 | 单调写 | 先读后写 |
---|---|---|---|---|---|
"majority" |
"majority" |
✅ | ✅ | ✅ | ✅ |
"majority" |
{ w: 1 } |
✅ | ✅ | ||
"local" |
{ w: 1 } |
||||
"local" |
"majority" |
✅ |
如果因果一致性表示持久性,那么从表中可以看出,只有具有"majority"
读关注度的读取操作和具有"majority"
写关注度的写入操作才能保证所有四个因果一致性保证。也就是说, 因果一致的客户端会话只能保证以下方面的因果一致性:
- 定义一致性名词
Guarantees | 描述 |
---|---|
阅读您的文章 | 读操作反映了在其之前的写操作的结果。 |
单调读 | 读取顺序,后读的内容一定比先读的内容新或者相同 |
单调写 | 后续发送的写,必须在前面发送的写完成后才能执行 |
写跟随读 | 写入时的数据状态必须包含之前的读取操作的数据状态 |
隔离级别
- 阅读未提交
使用"local"
或"available"
读取关注点的客户端可以读取数据,这些数据随后可能会在副本集故障转移期间回滚。
读未提交是默认的隔离级别,适用于mongod
独立实例以及副本集和分片群集。 - 阅读未提交的单文档原子性
对于单个文档,写操作是原子的。即,如果写操作正在更新文档中的多个字段,则读操作将永远不会看到仅更新了某些字段的文档。但是,尽管客户端可能看不到部分更新的文档,但未提交的读取意味着并发的读取操作仍可以在使更改持久化之前看到更新的文档。 - 读取未提交和写入多个文档
当单个写入操作(例如db.collection.updateMany()
)修改多个文档时,每个文档的修改都是原子的,但整个操作不是原子的。
对于需要原子性地读写多个文档(在单个或多个集合中)的情况,MongoDB支持多文档事务:
在版本4.0中,MongoDB支持副本集上的多文档事务。
在4.2版中,MongoDB引入了分布式事务,它增加了对分片群集上多文档事务的支持,并合并了对副本集上多文档事务的现有支持。
写关注
:当写入关注程度高时,MongoDB必须等待一段时间才能响应,因此此类的关注等级适合那些数据非常重要,必须保证数据的正确性的数据,该类数据可以承受数据的时效慢的问题,比如关于金钱的修改操作等。而写入关注程度较低时,则是不关注写入操纵是否成功,直接返回结果,此类写入关注适合哪些要求时效性高,数据不太重要的操作,比如日志记录等等。
下面是MongoDB的写入关注等级表
等级 | 描述 |
---|---|
-1 | 忽略网络错误 |
0 | 不要求进行写入确认 |
1 | 要求进行写入确认 |
2 | 要求以写入到副本集的主服务器和一个备用服务器 |
majority | 要求已写入到副本集中的大多数服务器中 |
读关注
读取关注允许您控制从副本集和副本集分片读取的数据的实时性,一致性和隔离性。
通过有效使用写入关注和读取关注,可以适当调整一致性和可用性保证的级别,例如等待更强的一致性保证,或者放松一致性要求以提供更高的可用性。
现在读取关注分为了一下几个级别:
级别 | 描述 |
---|---|
“local” | 查询返回实例的最新数据。不保证数据已被写入大部分副本集成员(即可能回滚)。 默认操作:1.反对读取主节点 2. 如果读取与因果一致的会话相关联,反对读取从节点。local可用于与因果一致的会话(causally consistent sessions.)。 |
“available” | 3.6版本中的新功能。查询返回实例的最新数据。不保证数据已被写入大部分副本集成员(即可能回滚)。 如果读取与因果一致的会话没有关联,则默认读取从节点。 对于分片集合,”available”读取关注提供了可能在各种读取关注点之间的最低延迟读取,但是以一致性为代价,因为”available”读取关注可以返回独立文档。 可用的阅读关注无法用于因果一致的会话。 |
“majority” | 查询返回已由大多数副本集成员确认的实例最新数据。读取操作返回的文档即使在发生故障时也是持久的。 要使用”majority”读取关注级别,副本集必须使用WiredTiger存储引擎( WiredTiger storage engine)和选举协议版本1( protocol version 1)。 阅读关注的”majority”可以使用与会话一致的会话。 |
“linearizable” | 查询返回的数据反映了在读取操作开始之前完成的所有成功的多数确认写入操作。在返回结果之前,查询可能会等待并行执行写入操作,以传播到大多数副本集成员。 如果大部分副本集成员在读取操作后崩溃并重新启动,如果writeConcernMajorityJournalDefault设置为默认状态true时,则读取操作返回的文档是持久的。 在writeConcernMajorityJournalDefault设置为false的情况下,MongoDB不会等待w:”majority”写入到磁盘日志中,然后再确认写入。因此,在给定副本集中的大多数节点的瞬时丢失(例如,崩溃和重新启动)的情况下,大部分写入操作可能会回滚。 您值可以为主节点的读取操作指定”linearizable”的读取关注 阅读关注linearizable不适用于因果关系一致的会话。 linearizable读取关注保证仅适用于读取操作指定唯一标识单个文档的查询过滤器。 |
读取偏好(Read Preference)
阅读偏好描述mongodb客户端如何将读取操作路由到副本集的成员。
注:
- 指定读取偏好时要小心:除主节点之外的其他模块可能会返回过时数据,因为使用异步复制时,从节点中的数据可能不会反映最近的写入操作。
- 读取偏好不会影响数据的可见性;即客户端可以在确认或传播给大多数副本集成员之前看到写入结果: 无论写入问题如何,使用”local” 或”available”读取关注的其他客户端都可以在写入操作被确认给发出客户端之前看到写入操作的结果。 使用”local” 或”available”读取关注的客户端可以读取可能随后回滚的数据。
阅读偏好 | 描述 |
---|---|
primary | 默认模式。所有操作都从当前副本集的主节点中读取。 |
primaryPreferred | 在大多数情况下,读取操作从主节点中读取,但如果主节点不可用,操作会从从节点读取 |
secondary | 所有的读取操作都从当前副本集的从节点中读取 |
secondaryPreferred | 在大多数情况下,读取操作从从节点中读取,单数如果没有从节点是活跃有效的,从主节点中读取 |
nearest | 操作从具有最少网络延迟的副本集的成员读取,而不考虑成员的类型。 |
客户会话和因果一致性保证
为了提供因果一致性,MongoDB 3.6启用了客户端会话中的因果一致性。因果一致的会话表示具有"majority"
读关注点的读操作和具有"majority"
写关注点的写操作的关联序列具有因果关系,这由它们的顺序反映出来。 应用程序必须确保一次只有一个线程在客户端会话中执行这些操作。
对于因果相关的操作:
参考资料:
MongoDB: 通过ReadConcern 来处理备库一致读的问题
MongoDB学习笔记(九)——Write Concern、getLastError、Read Concern、Read Preference