“共享内存系统没有显式信道状态,进程通过读写对象交互。ABD 寄存器用请求、响应、单调版本与多数写回模拟原子寄存器;用共享队列模拟收件箱又依赖队列原子性。偷偷加入所有节点可读的数据库或共享磁盘…”
形式陈述 ​
ABD 把原子寄存器实现在异步消息传递系统上。本页先完整说明原始单写多读(SWMR)的无界版本号方案,再在相同故障模型下构造多写多读(MWMR)扩展。
单写多读:模型与协议 ​
SWMR 中,一个指定写者调用 write(v),任意多个读者调用 read();每个客户端上一操作返回后才发起下一操作。固定
正确客户端与正确副本之间的请求和响应最终交付,正确进程公平地执行本地步骤、处理每个请求。消息可以乱序,信道不复制消息,也不能伪造或篡改。客户端也可崩溃;终止承诺只针对正确客户端。客户端和副本可以由同一进程承担,但停止服务的副本仍计入
每个副本保存一对
QUERY(id,phase):回复当前,并回显请求身份。 UPDATE(id,phase,t',v'):若,把整对状态替换为 ;否则保留原状态。随后总是回复确认,包括版本较旧、状态未变的情况。
每个操作使用不复用的身份,例如 (client,sequence);查询与传播阶段另有不同 phase。客户端只接受匹配本操作、本阶段的回复,并按不同副本身份计数。重复确认只能算一次,旧操作的迟到确认不能凑数。这里的确认表示“处理后版本至少为
操作流程如下,向全体发送可以由依次发送组成,客户端崩溃可能截断发送前缀。
- 写: 写者将计数器加一得到
,向全部副本发送 UPDATE(id,write,t,v),收齐个不同副本的匹配确认后返回。 - 读的查询阶段: 向全部副本发送
QUERY(id,query),等待个匹配回复;选出其中版本最大的整对 。 - 读的写回阶段: 向全部副本发送
UPDATE(id,readback,t,v),等待个匹配确认,然后返回所选的 。读者不增加版本,也不在写回期间更改本次返回值。
固定多数下的多写多读扩展 ​
MWMR 允许不同客户端并发写入同一个寄存器,仍要求每个客户端的操作良构。沿用上述固定副本集、正确多数、可靠最终交付和 crash-stop 假设。每个写者拥有互异且来自固定全序的身份
将整数版本替换为标签
计数
MWMR 的读写都执行两个通信阶段:
- 写前查询。 写者
向所有副本发出 QUERY,收齐 个有效回复。设回复中的最大标签为 ,生成新标签 ,与本次输入值 配对。 - 写传播。 向所有副本发送 UPDATE
,收到 个有效 ACK 后返回。各次发送仍是独立动作,崩溃可以截断发送前缀。 - 读查询。 向所有副本查询并收齐
个有效回复,选择最大标签及其所携带的值 。 - 读写回。 将所选整对发送给所有副本,收齐
个有效 ACK 后返回所选的 。读者不生成标签;后来遇到更高并发标签,也不更换这一次已经选好的返回值。
步骤 1–2 属于一次写,步骤 3–4 属于一次读。这里的“双阶段写”是通常称为 MWMR ABD 的直接扩展;1995 年 ABD 原文的 Figure 2 是上面的 SWMR 构造,其多写者结果通过模拟已有共享内存构造得到。后续 Lynch–Shvartsman 工作给出了固定 quorum 的直接双阶段协议并进一步处理动态 quorum。本页只取其中固定多数的思想,按自己的可靠消息接口给出简化协议与完整证明。
直觉
一次写返回,意味着足够多副本已经保存“不早于这次写”的状态。下一次读不必联系同一批副本:任意两个大小为
然而,读可能撞见尚未完成的写:某个新值才传播到一个副本,读者就选中了它。此时写者没有建立多数证据。读者若立刻返回,后继读可能完全错过这个值。写回让读者在公开结果前,亲自把“此版本已经被观察到”的证据传播到多数。它帮助尚未完成的写成为后继观察必须尊重的历史。
服务器只接受更高版本,使迟到消息不能撤销这份证据。旧版本请求仍须确认:某个读者正在传播版本
多写者增加的难点是:一个刚开始工作的写者,私有计数器可能远远落后于已经完成的读写。ID 可以打破两个并发写者选择同一计数时的平局,却不能让“后来才调用”的写自动排在前面所有完成操作之后。写前查询负责接收多数中已有的标签下界,再把计数加一;读后写回负责让一个已公开的读结果也拥有这样的多数下界。两者共同把客户端之间的实时先后传到服务器状态中。
这与逻辑时钟的标量加身份形式相似,但标签生成的事件不同:此处的计数来自一次 quorum 查询,而非每发生本地事件就加一。标签较小的并发写完全可能较晚返回。证明所需的只是实时先后必然得到相应标签不等式,不需要由标签反推消息因果或墙钟时间。
例子与边界
三个副本上的新旧倒退 ​
令
若删掉读的写回阶段,
真实 ABD 在
从相交证明到完整原子历史 ​
关键不变量有两个:每个副本版本单调不降;每个非初始
给每个完成读赋予它选中的版本,每个写赋予自己产生的版本。上面的引理说明:写返回后才开始的读,其版本不小于该写;读返回后才开始的读,其版本不小于前读,因为前读也完成了传播。还有两种实时关系:先写后写的版本严格增加;若一个读返回后才调用某写,该写版本也严格大于读版本,因为读到的版本已经由单写者产生,而新调用尚未发生。
因此可为每个有限历史构造合法顺序:保留全部完成操作,以及作为完成读来源的未完成写;给这些未完成写补上响应,删除其他 pending 操作。将写按版本递增排列,把版本
尤其不能因为写者未收到多数确认,就从历史中删除已经被完成读观察到的写。上例允许把 pending 的
六个操作:迟到确认与崩溃写的来源 ​
仍取三个副本 A、B、C 和
下表用
| 时刻 | 操作与本阶段的证据 | A | B | C |
|---|---|---|---|---|
| 0 | 初始化 | |||
| 1 | ||||
| 2 | ||||
| 3 | ||||
| 4 | ||||
| 5–6 | ||||
| 7–9 | ||||
| 10 | ||||
| 11–13 | ||||
| 14–17 | 写者 1 调用 |
|||
| 18–20 |
两个初始查询都只看到计数
把崩溃写
MWMR 的不变量与完整线性化证明 ​
同一标签只携带一个写值 ​
服务器标签单调不降,直接来自 UPDATE 只接受严格更大标签。每个正标签最初由一次写产生,读者只转发原有整对;因此只要证明不同写不会生成同一标签,就能归纳得出“同一标签永远对应同一值”。不同身份的写有不同第二分量。对同一身份的两次连续写,前次已经返回才会调用后次;前次确认多数与后次查询多数相交,交点在确认时已达到前次标签,以后不会降低。因此后次查询得到的最大计数不小于前次计数,加一后严格更大。跨越任意多次同身份写也同理。初始标签由初始化单独提供,不会被普通写生成。
这也解释了相等标签 UPDATE 不必替换值:相等标签的合法消息携带相同值,保留原状态不会丢失另一项写入。该结论依赖消息不能伪造、同一写者不并行复用身份,而不是仅靠字典序的定义。
多数如何把下界传给下一次查询 ​
设某操作的传播阶段以标签
因此
给每个完成读赋其选中标签,给每个已经生成标签的写赋其新标签。若
| 先完成的操作 | 后调用的操作 | 标签关系与理由 |
|---|---|---|
| 写 |
读 |
|
| 读 |
读 |
|
| 写 |
写 |
|
| 读 |
写 |
最后一行正是多写者情况下不能借用“唯一写者早已生成该版本”来证明的地方:承担这项工作的机制变成了写前查询。
从标签构造整个历史的顺序见证 ​
取任意有限历史,保留全部已完成操作。对每个读到非初始标签的完成读,再保留生成该标签的唯一来源写;若来源写 pending,就在历史末尾给它补上响应。删除其余 pending 操作,包括未完成读。来源写可能只传播到一个副本便崩溃,这不会改变上述选择。
将所有保留写按标签严格递增排列。每个读放在同标签来源写之后、下一更大标签写之前;初始标签的读放在所有普通写之前。同标签的读按原实时偏序的任意线性扩张排列。因为写标签唯一,这条规则不会在两个同标签写之间发生歧义。
检查实时顺序即可确认构造有效。不同标签操作的实时边由四种不等式保持;同标签读之间的边由线性扩张保持;同标签的写在读之前,而该读不可能在来源写调用前就返回,因为其标签尚未产生。补全的写没有原始返回,所以不会凭空产生一个必须排在后来调用之前的返回事件;但若某完成操作先于来源写调用,其标签关系仍由相同查询引理约束。这样所有原实时边都保留,每个读的最近前驱写又恰好是同标签来源写,满足线性一致性的顺序寄存器规格。
这是整个历史的线性化证明,不必把每次查询中某条消息的处理瞬间指定成固定线性化点。特别是并发写的标签顺序可以与响应顺序不同,只要没有倒置非重叠操作的实时边。
三处删减分别破坏什么 ​
只用私有计数器加身份,删去写前查询。 让身份 2 的首写以
删去读后写回。 让一个新写只把
仅在标签真正替换时 ACK。 某低标签传播仍在途中,更高并发写先更新全部正确副本。低标签请求到达后没有任何副本替换状态,若因而都不 ACK,正确客户端就永远等不到多数。单调性仍在,却失去了终止;相等标签也应确认,否则读者把刚查到的标签写回原副本便可能被无谓阻塞。
推论与应用
终止与通信成本 ​
至少
在不重传的上述可靠消息接口下,每阶段最多
MWMR 标签还包含写者身份,且请求身份不能复用;本页没有提供固定比特空间的循环回收办法。若
寄存器接口的边界 ​
ABD 说明可靠消息、正确多数和读后写回足以构造读写对象;写前查询使这套证据传递进一步覆盖多写者。它没有实现任意对象上的原子读改写,也不把多个寄存器的一组读自动变成快照。本页的一阶段写依赖唯一写者,双阶段写则允许多个良构客户端并发写;有界版本、恢复和重配置仍各需独立协议。
自测:在三副本例子中,把
参考资料
- Hagit Attiya, Amotz Bar-Noy, Danny Dolev, “Sharing Memory Robustly in Message-Passing Systems”, Journal of the ACM 42(1), 1995, pp. 124–142。§2.1 的模型、§3 的通信原语、§4 Figure 2 与 Lemmas 4.3–4.6、Theorem 4.9 给出无界单写多读构造;§5 的有界版本是另一构造。本文显式携带值、用操作身份区分消息,以固定严格多数表述其核心协议。
- Nancy Lynch and Alex Shvartsman, “Robust emulation of shared memory using dynamic quorum-acknowledged broadcasts”,1996-12-02 作者版,§4.1(印刷页 8–10)的固定 quorum 算法、§4.2 的原子性结论及 Appendix B 的 Lemmas 4.2–4.4 证明。这里引用作者版定位,不以其分页代指 1997 会议短版;本文也不采用其动态配置、重启和底层广播接口的完整模型。
- James Aspnes, Notes on Theory of Distributed Systems,2026-04-25 版本,§§17.2–17.5,印刷页 144–148;§17.5 给出写前多数查询与二元标签扩展。