← 学习库CAP与BASE学习手册分布式理论与一致性设计

CAP与BASE学习手册

从网络分区的限制,走到最终一致性的实现。

章节01 / 完整阅读

为什么多放一份数据,反而多了一道难题

01 / THE PROBLEM

单节点保存x=0时,写入与读取可以围绕同一份状态协调。为了让一个节点故障后仍有副本可用,我们把数据复制到节点A与B。新的问题随之出现:A接到x=1,B什么时候知道这次更新?写入成功应等待几个副本?A与B之间失联,但两边都还能接到客户端请求时,B应该如何回答?

网络分区是节点之间无法正常通信,不要求节点宕机。分区两侧可能都在运行,也都能接收各自客户端的请求。一个请求超时,只能说明没有及时收到结果;它不能证明远端没有执行。这种“结果未知”会贯穿复制、选主、消息投递和分布式事务。

先明确业务承诺。余额不能透支、库存不能超卖是业务不变量;“已成功的写入,后续读取必须看到”是观察数据的规则;“推荐列表允许落后”是可接受的服务行为。它们相关,但不能混成一个笼统的“一致性”。

理论背景:Gilbert与Lynch的CAP证明。

章节02 / 完整阅读

CAP:分区发生时,不能同时保证C与A

02 / PRECISE DEFINITIONS

性质精确定义与边界常见误解
C · Consistency
一致性
原始证明使用原子一致性,即线性一致性:操作看起来在调用与返回之间的某一瞬间生效,并尊重实际时间先后。写入成功返回后才发起的读取,不能返回被该写入覆盖的旧值。不是要求所有副本在每个物理瞬间都相同;也不是ACID中业务约束的一致性。
A · Availability
可用性
非故障节点收到的每个请求最终都应得到符合该操作语义的响应。该模型不承诺固定毫秒数,因此不等于工程中的延迟SLO或99.99%在线率。返回HTTP200却不给有效读取结果,或者直接拒绝操作,并不兑现原操作的可用性。
P · Partition tolerance
分区容错性
即使节点间消息丢失导致分区,也要讨论系统能否维持所承诺的性质。它是必须面对的故障条件,不是一个能靠配置关闭的网络现象。不能通过“不要P”阻止网络断开;跨节点系统仍须定义分区时的行为。

结论是:在允许网络分区的异步模型里,无法对所有执行同时保证线性一致性和可用性。没有分区时,系统可以同时提供C与A;分区时,可继续服务的操作、可服务的节点和需要等待的操作会不同。因此“三选二”适合帮助记忆,但不足以指导具体接口的设计。

CP通常表示分区时优先保持一致性,部分节点或操作失去可用性;AP通常表示分区两侧仍可按较弱一致性语义服务。AP可以提供最终一致性或因果一致性,但不满足这里的线性一致性。CA只能在排除分区的假设或限定范围内讨论,不能作为跨机房系统逃避分区的保证。

定义依据:CAP原论文;设计边界:Eric Brewer的十二年回顾。

章节03 / 完整阅读

两副本推导:B不知道的事情,不能凭空回答

03 / REASONING THROUGH A PARTITION

① 初始状态A:x=0
B:x=0
② 网络分区A ↛ B
两侧客户端仍可访问
③ A返回写成功客户端写x=1
A:x=1,B未知
④ 随后读B返回0:违反C
等待或拒绝:牺牲A
图1 · 以A已经确认写入为前提,B面临的取舍。系统也可以在③就阻止写入成功。

假设A已经把x=1确认给客户端,随后另一个客户端向B读取。B无法区分“A写入了1”和“A根本没有收到写入”这两种执行。如果B保持可用、直接返回本地的0,就在第一种执行中破坏C;如果B等到通信恢复才能确定最新值,永久分区下请求无法完成,就破坏A。猜测返回1同样不行,因为第二种执行并没有这次写入。

另一个选择是A在无法取得协议要求的确认时,不宣布写入成功。这样避免了上述已完成写入后的旧读,但写操作失去可用性。三节点共识系统在分成“2+1”后,可以让持有多数的分区按协议继续推进,少数侧不能独立提交新写。CP不意味着整个集群必然停机。

正常模式复制与协调
兑现读写承诺
检测超时可能分区或延迟
按策略限制操作
分区模式等待/拒绝风险操作
或记录可合并的更新
恢复模式同步历史、解决冲突
修复业务影响
图2 · 分区管理包含检测、受限运行和恢复;超时不是网络分区的确定证明。

恢复不能只比较最终字段值。如果两侧都对“只剩一件”的库存接受扣减,随后把数字合并成同一个值,也不能撤回已经向两个买家承诺的商品。必须知道操作历史和外部影响,决定拒绝、预分配库存额度,或者退款补偿。冲突解决规则也是系统语义的一部分;“最后写入覆盖”可能直接丢失某次业务更新。

推导参考CAP原论文;恢复过程参考Brewer对分区管理的讨论。

章节04 / 完整阅读

BASE:把暂时落后变成可管理的状态

04 / ENGINEERING WITH BASE

BASE是一组工程设计原则,不是与CAP相同层级的不可能性定理。它允许适当降低即时一致性的要求,让系统在部分故障或异步传播期间继续完成有价值的工作,同时设计状态收敛的路径。

原则含义业务案例与约束
BA · Basically Available
基本可用
故障时保留约定的核心能力,允许部分功能降级或延迟。订单已可靠保存后,积分服务暂时不可用,页面显示“积分待到账”。这不代表所有原操作都满足CAP的A。
S · Soft state
软状态
允许存在暂时未收敛的中间状态;即使没有新的外部请求,状态也可能因复制、后台处理或过期而变化。“待发积分”经后台消费变成“已到账”。软状态不等于不持久化,也不允许任意篡改业务状态。
E · Eventually consistent
最终一致性
在停止新更新、通信与处理恢复,并满足传播和冲突解决条件后,相关副本最终收敛。跨服务业务流程需要另外定义一致的终态与业务约束。每个有效订单对应且仅对应一笔有效积分流水。业务需要定义正常延迟目标、异常告警和修复责任;理论性质本身不给固定时限。

最终一致性不是“暂时不一致,过一会儿自然会好”。消息永久丢失、重试一直失败、冲突没有规则,都会阻断收敛。数据副本变得相同,也不自动说明业务正确:两个副本都保存了错误余额,仍然是同样的错误。

延伸阅读:Dan Pritchett:BASE: An ACID Alternative;收敛与读写观察:Werner Vogels:Eventually Consistent — Revisited。以下业务方案是教学设计,独立说明实现条件。

章节05 / 完整阅读

CAP、BASE与ACID分别回答什么

05 / DIFFERENT QUESTIONS

概念关注的问题案例中的位置
CAP发生网络分区时,能否同时兑现线性一致性和可用性?不能取得必要的复制确认时,余额写入能否成功?
ACID事务的原子性、业务约束一致性、隔离性和持久性如何保证?同一本地事务内,订单记录与待发送事件一起提交或回滚。
BASE允许哪些中间状态与降级行为,如何最终收敛?订单成功后,积分可暂时待到账,后台可靠推进并核对。

ACID里的C侧重业务不变量,例如转账前后总金额守恒;CAP里的C侧重并发读写的可观察顺序。ACID也不自动意味着所有读取线性一致:隔离级别、读副本策略、复制与故障切换都会影响实际语义。

局部ACID与跨服务BASE可以组合。订单数据库内部用事务保证订单与事件同时持久化;积分数据库内部用事务保证去重记录与积分变更同时提交;两库之间通过异步投递形成有条件的最终收敛。这样没有获得跨库原子事务,而是明确接受并管理“订单已完成、积分未到账”的窗口。

两种C的区别与局部事务组合,参考Brewer的ACID、BASE与CAP讨论及Vogels的一致性模型说明。

章节06 / 完整阅读

订单与积分:把“最终”落实到每个故障窗口

06 / A COMPLETE DELIVERY PATH

教学场景:订单支付结果已经得到可靠确认,每笔有效订单应发一次积分。我们允许到账延迟,但不能因为进程重启漏发,也不能因为重复消费多发。支付确认本身以及退款后的积分冲正是独立流程,不能由下面这条发积分链路自动保证。

① 本地事务订单状态+outbox事件
同库一起提交
② 后台投递扫描待发送事件
确认后标记已投递
③ 消费事务业务唯一键去重
流水+积分一起提交
④ 核对与修复找未完成或错误终态
补发/冲正/人工处理
图3 · 可靠保存、允许重复、事务幂等和异常修复共同构成收敛路径。

第一步,堵住漏发窗口。在订单库同一事务里更新订单,并写入outbox事件,例如(order_id, event_type, version)及载荷。提交后才向客户端确认订单状态。若仅在提交订单后调用MQ,进程可能在两者之间崩溃,留下永久没有消息的订单。outbox把“发送意图”保存为可恢复的数据。

第二步,承认重复投递。后台发布器取得MQ确认后再标记已投递。若MQ已接受但确认丢失,或者发布器在标记前崩溃,恢复后会再次发送。因此链路按至少一次处理来设计。持久化配置、重试、消息保留期限与故障恢复必须满足业务条件;单有outbox表不会自动保证投递成功。

第三步,事务内保证业务幂等。积分库对业务事件设唯一约束;去重记录、积分流水和账户积分更新在一个本地事务里提交。唯一键必须对应真实业务语义:若不同消息ID可以描述同一订单发积分,就不能只按消息ID去重。并发重复事件由唯一约束和事务串行化相应结果,不能只做“先查询是否存在”。

如果先登记“已处理”再另行加积分,中间崩溃会永久漏发;如果先加积分再另行登记,中间崩溃会导致重复加分。事务成功后才确认消费;事务已成功而消费确认丢失时,再次消费应命中去重,返回已有业务结果。

故障窗口持久状态恢复动作与边界
订单事务提交前崩溃订单变更与outbox均未提交。客户端按业务请求键查询或重试;不能凭超时判断是否失败。
提交后、发送前崩溃outbox事件仍待发送。发布器恢复扫描;事件需要有可追踪的状态和重试计划。
MQ接受后、标记前崩溃事件可能已入队,本地仍待发送。允许重发,由消费端业务唯一键拦住重复效果。
消费事务提交后、确认前崩溃流水和积分已持久化。再次消费按幂等结果完成,不能重复加分。
毒消息或服务持续异常事件长期未达到终态。退避重试、告警、隔离、对账修复或人工处理。移入死信不等于业务已收敛。
退款事件乱序或晚到发放与冲正可能交错。设计订单版本、状态机和唯一冲正流水;不能假定不同队列天然有序。

第四步,用对账识别不收敛。比较有效订单与积分流水,区分未发、重复、已退款但未冲正。补发必须仍走同一幂等入口;补偿是新的业务动作,应保存关联原交易的流水,不能简单删除历史。监控待处理年龄、失败重试次数和对账差异,比只看MQ堆积量更接近业务结果。

对外状态也要准确。“订单成功,积分待到账”与“积分已到账”是两个承诺。必须先可靠保存原操作或其处理意图,才能返回“已受理”;将请求放入内存或直接返回成功,不能替代可靠受理。

上述outbox流程、故障分析与约束是教学方案,并非声称某个现有项目采用了该实现。可结合RocketMQ手册继续分析投递、重试与消费位点。

章节07 / 完整阅读

按操作选承诺,不给整个产品贴一个标签

07 / CHOOSE PER OPERATION

操作与风险可以接受的行为必须进一步回答
余额扣减、严格库存预占在不能确认约束时,限制提交或返回待确认;也可预先分配可独立使用的额度。谁有扣减权限?如何避免旧主继续写?超时后如何查结果?预分配额度如何回收?
推荐列表、搜索索引允许返回稍旧的数据,更新异步传播。可落后多久?删除与权限变更是否另有严格约束?如何发现更新永久遗漏?
订单与积分联动订单可靠提交后,积分待到账;最终推进到业务终态。业务幂等键是什么?退款怎么冲正?持续失败谁修复?
服务发现与配置按数据类型、协议与读取路径分析,可能涉及缓存、共识或异步传播。缓存能用多久?写成功的确认边界是什么?读取是否满足线性一致性?

共识提交不自动保证任意缓存或副本读取线性一致。多数派交集也不是一句R+W>N就能证明整个实现正确:并发写、版本选择、成员变更和读取校验仍要分析。读取策略、故障模式与协议路径必须一起说明。

阅读Nacos时,可继续追踪临时实例Distro、持久实例共识路径与配置存储,分别确认权威状态、传播延迟和故障边界。服务注册、配置更新以及客户端缓存不是同一个操作,不能一句“Nacos是AP”或“Nacos是CP”覆盖全部行为。

设计时按这个顺序追问:数据范围是什么 → 哪个操作必须保证什么 → 分区时哪些节点能服务 → 允许什么中间状态 → 恢复依赖哪些条件 → 怎样验证终态与业务约束。每一步都应能对应到状态、协议或恢复机制。

章节08 / 完整阅读

知识回顾与自测

08 / EXPLAIN IT BACK

CAP描述的是网络分区下的限制:这里的C是线性一致性,A是非故障节点收到的每个请求最终完成。两个副本失联后,如果一侧已经确认新写入,另一侧仍返回旧值就失去C;等待或拒绝则失去A。BASE是一组工程设计原则,允许核心功能基本可用、存在软状态,并在条件满足后最终收敛。实现时不能只说异步消息,而要说明可靠保存、业务幂等、重试、补偿与对账。我会按具体操作做选择,比如余额扣减守住约束,积分到账允许延迟;局部用ACID,跨服务管理最终一致的窗口。
为什么CP系统分区后可能还有部分节点可用?

三节点分成2+1时,多数侧可按共识协议继续提交,少数侧不能独立提交同一份数据的新写。CAP的A要求每个非故障节点的请求都完成,所以“多数侧可用”仍不等于满足整体A;读请求还要看读取协议。

最终一致能否直接保证库存不超卖?

不能。把副本最后合并为同一个库存数,不会自动撤回两个已确认订单。需要协调限制扣减、预分配额度等方案,或者明确接受超卖并提供业务补偿。

消息发送超时,能否认为没发成功并重发?

结果未知:消息可能已被接受但确认丢失。可以在可靠记录和重试规则下重发,但消费端必须按业务语义幂等;外部副作用还需要对端幂等键、结果查询或补偿机制。

为什么本地事务和BASE能同时使用?

它们的范围不同。订单与outbox同库原子提交,积分与去重流水同库原子提交;两库之间仍有传播窗口,靠投递和恢复机制推进到正确终态。

“返回受理中”能否绕过CAP?

不能。它改变了接口承诺:可靠保存请求意图可以完成受理操作,但原写入尚未完成。客户端仍需查询终态,系统仍要承担后续处理、幂等和恢复责任。

上线前怎样验证这条链路?

在提交前后、MQ确认前后、消费提交前后注入进程崩溃;并发重复投递、延迟和乱序事件;恢复后核对每笔业务的唯一流水、积分总额、outbox终态和告警。这里提供验证思路,没有宣称已运行生产故障实验。

章节09 / 完整阅读

原论文精读:Gilbert与Lynch究竟证明了什么

09 / READ THE ORIGINAL PAPER

论文为Seth Gilbert与Nancy Lynch的Brewer’s Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services。以下解析依据链接中的12页PDF,页码均按PDF页序计算。先读前面的两副本例子,再读本节的执行构造,便能把“CAP三选二”还原成有假设、有量词、有反证过程的理论结论。

核心结论:在允许网络分区的模型中,不存在一种读写算法,能够对所有允许的执行,同时保证线性一致性和可用性。限制针对算法能兑现的承诺,不取决于机器是否足够快,也不要求节点宕机。

9.1 阅读地图:不只有一个CAP证明

PDF位置原文内容阅读时要回答的问题
第2—4页 · §2原子读写对象、可用性、分区容错的形式化定义。C究竟是哪一种一致性?A是否有固定响应时限?哪些故障被模型允许?
第4—5页 · 定理1纯异步模型中的不可能性证明。两种执行为什么对读取侧不可区分?矛盾发生在哪里?
第5—6页 · 推论1.1即使只要求无丢消息的执行保持原子一致,也有额外限制。“消息永久丢失”和“消息只是很慢”能否区分?
第6—7页 · §3.2分别保留两种性质的简单构造。每个构造依赖什么假设,放弃了哪项保证?
第7—8页 · 定理2与§4.3有时钟和已知时间上界时,不可能性仍成立,但能提供不同的降级保证。知道通信超时,是否等于知道远端数据?
第9—11页 · 定义3与定理4Delayed-t一致性及中心节点协议的构造。恢复后多久、以什么条件,重新约束跨节点操作顺序?

9.2 研究对象与模型:一个变量就足够暴露限制

研究对象是可读写的数据对象:初始值为v₀,客户端执行write(v)与read()。至少两个节点通过消息共同提供这个对象;客户端可向不同节点请求。这里不需要SQL事务或复杂业务。一个简单读写对象已经足以证明这些承诺不能同时实现,更多业务代码不会补足被分区切断的信息。

C是原子一致性,也称线性一致性。全部操作必须能安排成一个合法的总顺序,看起来各自在调用与返回之间的某个瞬间生效,并尊重实际时间先后:写完成之后才开始的读,必须返回该值或更晚写入的值。时间重叠的操作则可以选择合法顺序。它不要求所有物理副本每一瞬间都相同;内部传播可以有延迟,但客户端观察必须满足这一规则。

A要求每个非故障节点收到的请求最终完成。论文不规定多少毫秒内完成,因此这里的A既不同于响应延迟SLO,也不同于年度在线率。但不能永久等下去,或以任意错误响应替代成功完成的原读写操作。读写返回还必须与所承诺的对象语义结合讨论。

P通过允许任意数量的消息丢失来建模。跨分区消息可以永远到不了,分区内部节点却可以正常工作。论文明确不研究节点停止故障;证明只需要通信失效。定理1讨论公平执行:不能靠让一个正常节点永久得不到运行机会来制造反例,但公平调度不意味着跨分区丢失的消息必须被送达。

异步模型中没有时钟,节点根据收到的消息和本地计算决策。模型没有提供可用于区分“消息丢失”和“消息迟到”的有限通信时间上界。上述假设是后面证明能成立的条件,不能省略后只剩一句“分布式系统不可能一致”。

原文:§2定义,第3页;异步模型与定理1,第4页。

9.3 定理1:用三个执行,证明算法不存在

反证法先假设存在算法𝒜,能满足原子一致性、可用性和分区容错。将网络划成两个不相交、非空的节点集合G₁与G₂,两集合之间的消息全部丢失。设置初始值v₀=0,新写入值v₁=1。

执行请求与通信由假设推出的结果
α₁:只写G₁接到write(1),两侧没有其他客户端请求,跨分区消息均未到达。A要求写在有限的执行前缀内完成;不能等待另一侧到无限久。
α₂:只读没有任何写入,G₂接到read(),跨分区消息均未到达。A要求读取完成;C要求没有写入时返回初始值0。
α:先写后读先运行α₁直到写完成,再运行α₂的读取过程,跨分区消息继续丢失。G₂的观察与α₂相同,所以读取仍返回0;但C要求它返回1。
对照世界α₂没有发生写入
G₂未收到G₁消息
read()必须返回0
组合世界αG₁的write(1)已完成
G₂仍未收到G₁消息
随后read()按C必须返回1
图4 · 两个世界对G₂的本地观察可以完全相同,却要求不同的正确答案;这是不可区分性矛盾。

α₁没有给G₂引入任何客户端请求,也没有送达来自G₁的信息。可以安排G₂看到与α₂相同的本地事件。因此对G₂而言,组合执行α与只有读取的α₂不可区分。算法不能根据完全相同的输入与本地状态,凭空判断另一个世界是否完成了写入。

但组合执行里,写入已返回,读取才开始,二者没有时间重叠,不能把读取任意排列到写入之前来解释旧值。G₂返回0违反C;无限等待违反A;猜测返回1则在根本没有写入的α₂里违反C。因此最初假设的算法不存在。

量词是证明力量的来源。定理不是说某一种主从方案失败,而是说任何想兑现全部承诺的算法,都存在一个模型允许的执行使承诺不能同时成立。反例只需发生一次,就足以否定“对所有允许执行都保证正确”的声明;它不表示普通网络运行时每一次请求都会遇到这个问题。

原文:α₁、α₂与α的正式构造,第5页。

9.4 推论1.1:“最终没丢消息”不等于“消息足够及时”

尝试把要求放宽:所有公平执行中保持可用;只有在所有消息最终都送达、没有丢失的公平执行中,才保证原子一致;真正丢消息时允许旧值。推论1.1指出:在纯异步模型中,这组保证仍不能同时实现。

证明从定理1出发。一个始终保证A的算法,必然存在允许丢消息的公平执行α,在某个有限时刻返回违反原子一致性的结果。截取到这个结果为止的有限前缀α′,再构造另一个执行α″:保留此前相同的可观察事件,把尚未到达的消息解释为延迟,并在此后全部送达。

α″最终没有丢消息,但错误响应已经出现。把消息在之后补送,不能改写客户端已经观察到的操作历史。因此算法违反了它对“无丢消息执行”的原子一致承诺,假设再次矛盾。

这里构造的是另一个执行。不是把原执行里真正丢失的消息复活,而是让同一个有限观察前缀出现在“所有消息最终送达”的执行中。纯异步节点在响应时无法区分这两种未来。

这个结果不否定异步复制的最终一致性。被否定的是更严格的组合:分区时请求始终完成,同时所有最终无丢消息的执行从头到尾保持线性一致。消息后续抵达可以帮助收敛当前状态,却不能把过去已经返回的旧读变成线性一致。

原文:推论1.1,第5—6页。

9.5 “任意两个可实现”的构造,分别放弃什么

第3.2节不是只给口诀。C+P的例子是指定中心节点维护权威值,其他节点转发请求,收到确认再回复;通信失效时请求可能不完成。C+A可以在排除分区且消息送达的假设下采用同样的集中处理。A+P则可以放弃原子一致性,极端例子是读取总返回初始值,真实系统可进一步定义更有价值的弱一致性。

因此,AP标签本身没有规定旧值最多落后多久,也没有承诺业务最终正确;CA的构造排除了分区条件,并没有创造“永远不会分区”的网络。CP也不要求所有节点一起停止服务,只是不能要求所有非故障节点的每个请求都能继续完成。

原文:§3.2,第6—7页。

9.6 定理2:时钟能识别超时,不能创造远端信息

第4节加入更强的时间假设。每个节点有时钟,走速相同,但显示值不要求同步;消息要么在已知时间t_msg内到达,要么丢失;收到消息后的处理也有已知上界t_local。这里应按论文自己的定义理解“部分同步”,不要将它直接等同于所有其他文献中的同名模型。

定理2说明:即使有这些计时能力,只要允许任意消息丢失,仍不存在对所有执行同时保证A与原子一致性的读写对象。知道对方无法通信,并不等于知道对方有没有执行写入。

证明仍然构造G₁完成写入、G₂随后读取的分区执行。但这次时钟可观察,不能直接忽略经过的时间。作者在“只有读取、没有写入”的对照执行前加入长空闲区间,至少覆盖写入执行的时长,再将两个执行叠合。这样既保证写完成后读才开始,也保留G₂无法区分两个世界的条件,得到同样的旧读矛盾。

原文:模型与定理2,第7—8页。

9.7 为什么时间上界能改变降级保证

定理2仍成立,但推论1.1在这个模型中不再成立,因为模型已提供判断通信是否按时完成的能力。节点可先请求中心节点,等待2 × t_msg + t_local:请求去程、处理与回复回程。及时收到回复就用中心结果;超时则返回本地已知值或确认请求,接受原子一致性可能被破坏。

在全部消息按模型上界送达的执行中,可以保持原子一致性;丢消息时采取较弱的响应策略。这项能力来自模型增加的假设。生产系统设置500毫秒超时,只是选择等待预算,不能由此证明“凡是没丢失的消息都在500毫秒内到达”。网络拥塞、队列积压和进程暂停均可能使工程超时出现。

尤其要区分写请求的确认含义。论文讨论弱化的读写对象保证,不是在证明一个超时确认已经同步到全部副本,更没有证明它已经完成生产系统要求的持久化与业务副作用。

原文:§4.3,第8页。

9.8 Delayed-t一致性:恢复约束精确到操作顺序

定义3给出比“最终会好”更具体的弱一致性条件。它要求存在操作偏序P:所有写操作有序,所有读操作相对于写操作有序;每次读返回其在P中前一个写的值,没有前序写则返回初始值;P还要尊重各节点提交请求的顺序。这里的偏序P是数学记号,不是CAP中的分区容错P。

除此之外,它规定两种跨节点时间约束:整个执行的消息都正常送达时,保留原子一致性的实际时间顺序;发生丢消息时,若操作θ已经完成,随后存在一个长度大于t、没有消息丢失的区间,操作φ在这个区间结束后才开始,那么φ不能在P里排到θ之前。

操作θ完成
    ↓
正常通信持续超过t,期间没有消息丢失
    ↓
操作φ开始
    ↓
φ不能被解释为发生在θ之前

简单例子:没有其他写入时,write(1)已完成,随后网络正常超过t,再发起read(),后者不能仍表现得像这次写入从未发生。这个例子帮助理解定义,但完整条件是对读写操作顺序的约束,而不是一个不附条件的“数据只会落后t秒”指标。

第10—11页的协议变体使用中心节点C分配递增序列号,节点读取中心值或已缓存的最高已知序列号;写入与更新广播在超时后继续重试。原文将写重试等待约束为t − 4 × t_timeout以内,将中心重发等待约束为t − 2 × t_timeout以内,以安排恢复窗口中的传播;参数选择需让这些等待预算有意义。

定理4的证明把写操作按中心获知它们的顺序排列,把读放到其所返回值对应的写之后;再论证一段足够长的正常通信区间能让此前更新经中心传播,从而约束区间结束后开始的操作。这里是论文给出的协议与证明思路,不应直接复制成处理并发写、去重、节点崩溃和持久化的生产协议。

它不保证无限分区期间的数据同步,不保证网络刚恢复的一瞬间所有读就线性一致,也不提供库存不超卖、资金守恒等业务不变量的证明。现实系统的恢复时限还依赖重试、负载、积压和故障假设,不能直接把论文的t当成自己的SLA。

原文:定义3,第9页;协议构造,第10页;定理4,第11页。

9.9 结论边界:论文没有替我们做业务设计

  • 它没有证明所有分布式系统在正常通信时也必须放弃C或A;限制针对包含分区的全部允许执行。
  • 它没有证明CP意味着整个集群停机,或AP意味着可以任意返回错误数据;可服务范围与弱一致性语义仍需定义。
  • 它没有证明BASE和最终一致性自动保证业务正确;副本收敛与业务约束成立是两个问题。
  • 它没有证明超时等于失败;远端可能执行成功而回复丢失。
  • 它没有证明某个数据库、注册中心或消息系统整体属于CP或AP;必须分析具体操作、协议、读取路径和故障模式。
  • 它没有在本论文的模型中解决节点停止故障、业务事务、持久化与外部副作用;这些需要额外机制与证明。
“另一侧完成了写入”和“另一侧没有写入”,对当前节点可能完全不可区分,但线性一致性要求两个世界给出不同答案;可用性又不允许无限等待。CAP证明的是这种信息约束。工程设计随后要决定允许哪些操作等待、哪些观察暂时落后,以及满足什么条件才能恢复承诺。
闭卷自测:能否不看原文,复现证明?

画出G₁、G₂与初始值;构造只写α₁、只读α₂、先写后读α;指出A在哪两处保证完成,C在哪两处要求不同值;说明G₂为什么不可区分。再解释推论1.1为何构造“延迟后送达”的另一个执行,以及定理2为什么要加入空闲时间。最后写出Delayed-t恢复条件,而不只背诵“最终一致”。

章节10 / 完整阅读

参考资料与继续阅读

PRIMARY REFERENCES

理论定义依据原论文与作者文章;订单积分、outbox和故障窗口采用教学案例。下一步:Nacos的状态与协议路径 · RocketMQ的可靠投递与消费 · Redis复制与分布式锁边界。

全文搜索

输入关键词,搜索完整正文。