Skip to content

一致性:用户能观察到什么 ​

副本内部暂时不同步,不一定违反对外的一致性承诺;副本最终拥有相同数据,也不说明过程中没有返回过错误结果。必须用客户端看到的操作历史描述承诺。

线性一致性 ​

线性一致性要求每个操作看起来在“调用到返回”之间的某一瞬间完成,且这个全序尊重真实时间:如果写入 x=1 已返回,之后才开始的读必须看到这次写或更新的写。两个时间区间重叠的操作可以按任一合法顺序解释。

例如 A 的写在 10:00:00 返回,B 在 10:00:01 开始读取;读到初始值 0 不符合线性一致性。若 B 的读在写开始前就已发出,并在写完成后才返回,读到 0 仍可能合法,因为可以把读线性化到写之前。

单 leader 不能自动保证线性一致性。一个被隔离的旧 leader 可能仍以为自己有权服务,而多数分区已选出新 leader。如果旧 leader 直接读本地内存,就可能返回陈旧值。需要有效领导权确认、合适的读屏障或满足明确时钟假设的租约;配套模型用“读也写入复制日志”的较慢方案简化证明。

顺序一致性与因果一致性 ​

顺序一致性要求存在一个尊重每个进程自身操作顺序的全序,但不要求尊重所有进程之间的真实时间先后。它比线性一致性少了跨进程的实时约束。

因果一致性保留因果依赖:若读到消息后回复,其他人不应先看到回复、后看到原消息。彼此无因果关系的写可以在不同节点以不同顺序观察。Lamport 时钟满足“有因果关系则逻辑时间递增”,反方向不成立;向量时钟能表达更细的偏序,但代价与参与者管理相关。

最终一致性描述在不再有新更新、通信恢复等条件下副本最终收敛。它本身不保证读己之写、单调读、没有更新丢失;这些需要额外机制。CRDT 通过满足代数性质的合并规则构造收敛,例如集合并集是交换、结合、幂等的,但普通覆盖写不自动拥有这些性质。

CAP 应放在分区情境中理解 ​

分区时,两侧不能交换消息。若仍要求每个到达非故障节点的请求最终获得操作结果,就无法同时保证所有历史都符合单副本线性一致性;若要保住一致性,某些请求只能拒绝或等待。这里的 availability 是这种最终完成要求,不承诺固定毫秒数,也不是服务每月在线率;仅返回“无法处理”的错误不能把一次读写算作已完成。正常没有分区时,仍需权衡延迟、吞吐和一致性,但不能用“任意挑两个”代替具体分析。Gilbert 与 Lynch 的形式化论文

多数派读写为什么还不够 ​

三个副本,写入两个、读取两个,读写集合必相交。集合相交只是信息路径,仍要有版本选择、并发写排序、失败请求的解释以及读修复协议。简单设置 R+W>N 不能单独证明任意实现线性一致。

以 A、B、C 为例,某次写只到达 A,随后客户端超时。读 A、B 可能看到新值,而读 B、C 看到旧值。如果协议允许第一个读先返回新值、第二个晚发起的读又返回旧值,就会产生难以线性化的历史。如何传播观察到的版本,是协议的一部分。

用不变量选择实现 ​

需求需要明确的问题
配置与元数据读到旧版本是否可能启动错误服务?
点赞计数短暂不同是否允许?合并规则是否丢失增量?
库存扣减并发操作是否可能卖出超额库存?
搜索索引更新延迟是否在产品允许范围内?
自测:副本读最终都会更新,为何仍不能称为线性一致?

“最终”只约束未来收敛;线性一致性还约束已经发生的每次读写历史。写成功后发起的读取若返回更早的值,不能靠未来修正消除这次违约。

来源:MIT 6.5840 课程资料、Herlihy 与 Wing:Linearizability、Lamport:Time, Clocks, and the Ordering of Events。