2020-03-06

Paxos 与分布式强一致性

Views: 10339 | Add Comments

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

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

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

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

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

Basic Paxos 充满了各种工程上的错误暗示, 如果按它的暗示来, 你会犯各种错误. 例如, Paxos 暗示同步的是一个(唯一的一个)实例(key)和对应的状态(value), 工程上你不可能每一次都同步整个全量数据库, 对吧? 而且共识之后就不能更改, 哪有不能更改的数据库?

别提 Multi Paxos, 日志复制状态机是 Raft 的核心, 心里想着 Paxos, 但做着做着, 全是围绕复制状态机来做, 最终还是做成了 Raft 的样子.

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

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

总结:

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

Related posts:

  1. 关于 Paxos 论文中的迷惑之处
  2. Paxos vs Raft 的争论
  3. Paxos 算法难以理解吗?
  4. Paxos 和 Raft 的结构差异
  5. Paxos和Raft读优化 – Quorum Read 和 Read Index
Posted by ideawu at 2020-03-06 13:57:02 Tags: ,

Leave a Comment