2020-03-06

Paxos 与分布式强一致性

Views: 3452 | Add Comments

Paxos 有着"难以理解"的恶劣名声, 事实确实如此. 它用大段篇幅来做证明, 却对现实问题避而不谈. 例如最简单(常见)的问题: 怎么实现一致性读功能?

因为 Paxos 太难以理解, 所以无数人用各自不同的角度去理解 Paxos, 而且实现上千差万别和漏洞百出. 我觉得这种现象和一句名言类似: 不幸的家庭各有各的不幸. 但是, 学习 Raft 的人都很开心, 而且大家在实现(implement) Raft 协议时, 代码基本是一样的. 正如名言所说: 幸福的家庭都是相似的.

我也用我自己的角度去理解 Paxos, 我认为它最大的特点是不区别读和写. 简单说, Paxos 的读过程就是写操作, 就是在做数据同步.

首先, 无论使用何种一致性协议, 都无法解决在任何时刻副本数据不一致的问题. 也就是说, 一定存在某个时间点, 多个副本不一致. 这是无法解决的. 要解决的是读一致性, 即从观察者(用户)的角度看, 数据是一致的. 写操作永远都是"最终一致"的.

其次, Paxos "暗示"在读操作的时候进行数据同步, 以修复数据达到"最终一致性". 而工程上的常识是, 多个副本必须自动地最终一致, 而不依赖外界触发. 如果某个系统依赖 Paxos 的这种"暗示", 那么这个系统将是不可靠的, 也不是(最终)一致性的, 因为它没有时间概念, 只有操作序列概念.

补充一点: Paxos 充满了各种工程上的错误暗示, 如果按它的暗示来, 你会犯各种错误. 例如, Paxos 暗示同步的是一个(唯一的一个) key 和对应的全量值, 工程上你不可能每一次都同步整个全量数据库, 对吧? 不要提 multi-paxos, 因为你会被它错误地暗示而独立地处理每一个 key, 然后你实现不了数据 Catch Up, 无法实现副本的最终一致性.

对于读操作, Paxos 要求收到读请求的节点(Proposer)向其它节点发起数据同步操作, 也即所谓的 prepare-accept 两阶段. 在 prepare 的过程中, Proposer 收集其它节点的数据. Prepare 阶段除了同步数据, 还有一个作用是更新版本号(num), 之后就是 Proposer 将其所知的最新的数据同步到其它节点. 注意, 两阶段中间如果有失败, 不做回滚, 而是继续重试, 等最终成功, 或者放弃并告知用户.

再次注意, Paxos 并不是按数据版本号来返回最新的数据, 这种想法是错误的. 也不是所谓的多数派读(Quorum Read). 仅仅 Quorum Read 并不能保证强一致性, 因为某个节点可能随时上下线, 导致一会是多数派一会是少数派, 这种结果不是一致性的. 提一句, 这是个经典误解. Paxos 对一致性的保证, 来源于其无法读写, 都必须达成新的共识.

总结:

1. Paxos 读即是写, 读即是数据同步.
2. Paxos 既不依赖版本号返回最新的数据, 也不是所谓的多数派读.

Related posts:

  1. 关于 Paxos 论文中的迷惑之处
  2. Paxos vs Raft 的争论
  3. Paxos和Raft读优化 – Quorum Read 和 Read Index
  4. 为什么 Leader Based 的分布式协议 Raft 是更好的
  5. “一致性”是镜花水月
Posted by ideawu at 2020-03-06 13:57:02 Tags: ,

Leave a Comment