什么是分布式一致性

ideawu 2021-09-05 10:49

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

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

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

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

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

例如, 我们可能读取副本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. 分布式存储名词解析 – 一致性

[返回] [原文链接]