2021-09-05

什么是分布式一致性

Views: 21002 | Add Comments

在工程实践上, 分布式一致性和多副本有关系, 如果没有多副本, 就没有分布式一致性的问题.

多副本的定义: 多副本可以放在多台机器上, 也可以放在同一个进程内的不同内存地址内, 或者一个副本在内存, 一个副本在硬盘. 只要同一个对象出现在多处, 或者在多处被引用, 就是多副本.

各个副本的写入操作序列必须先经过共识, 按同样的顺序写入, 因此所有副本的状态将是最终一致的(相同). 但是, 有可能单独地读取某个副本, 这就导致读操作在不同副本上发生的顺序并不相同, 这显然会导致最终结果不一致(符合预期), 因为我们本能地知道, 顺序决定结果.

例如, 先写后读与先读后写, 显然读出来的结果不一样, 这个很显然. 因为日志序列的复制和执行必然是异步的, 绝对不可能所有副本在同一个时间点同时写入, 必然有一个时间差, 这也是很显然的. 因此, 如果轻率地去读取不同副本, 将可能导致读取的结果不同, 因为某个写入操作可能只在某个副本上执行了, 而在另一个副本上还没有执行, 所以读取的结果不同, 这是很显然的.

所以, 分布式一致性的本质在这里就显而易见了 - 那就是让操作在某个副本上发生的顺序符合我们的期望.

例如, 我们可能读取副本A, 也可能读取副本B, 或者同时读取副本A和B, 如果我们让所有的操作, 包括读和写在两个副本上发生的顺序相同, 那么, 结果必然是一致的, 这是很显然的.

这也是为什么有一些系统, 会把读请求放入 Raft 日志序列中进行同步的原因, 因为不同副本上的 Raft 的日志序列是相同排序的. 一条 Raft 日志序列是全序的, 但不相关的操作之间可能没有相互依赖和影响, 所以全序没有必要. 例如, 某些日志操作对象 a, 某些日志操作对象 b, 这两类操作之间没有必要排序, 让它们单独排序就可以了, 即所谓的偏序.

简单的实现方法就是做 Sharding, 把针对不同对象的操作拆分到不同的日志序列中, 也即所谓的 Multi Raft Group.

还有一种实现是不把读操作放到日志序列中, 而是通过停止等待, 等待某一个写操作在某个副本发生之后, 再执行读操作, 便保证了顺序. 这就是 Read Index 的本质, Read Index 先找出全部副本的最新的共识, 然后等最新的那条共识执行之后, 再执行读操作, 也就必然保证读操作发生在我们期望的那一次写操作之后.

Related posts:

  1. Paxos和Raft读优化 – Quorum Read 和 Read Index
  2. Raft 为什么不能直接 commit 前任的日志?
  3. Paxos 与分布式强一致性
  4. 什么是 Paxos 的日志空洞?
  5. 分布式存储名词解析 – 一致性
Posted by ideawu at 2021-09-05 10:49:53 Tags: ,

Leave a Comment