土法炼钢兴趣小组的算法知识备份

【数据库研究前沿】CRDT 与 CALM 定理再读:2025 的协调自由数据管理

文章导航

分类入口
database
标签入口
#crdt#calm#coordination-free#bloom#hydro#yjs#automerge#monotonicity

目录

这是【数据库研究前沿】系列的第 22 篇。本文把两条看起来不在同一条线上、但本质上在回答同一个问题的研究重新拼在一起:什么样的分布式数据管理可以不协调(coordination-free)。这个问题在过去十年反复被工程实践重新提出,每次以略有不同的面目出现——跨区域多写、本地优先(local-first)应用、协作编辑器、全球化计数、边缘侧同步——但骨架都一样。

一条线来自 UC Berkeley 的 Hellerstein 与合作者:2010 年 CIDR 的 The Declarative Imperative 提出 CALM 猜想,2020 年 CACM 正式把它写成 CALM 定理——一个分布式程序可以不协调地计算等价于集中式语义的结果,当且仅当它是单调的(monotonic)。围绕这条线长出来的是 Bloom/BloomL 编程语言、Dedalus 时序逻辑、以及近几年的 Hydro(Hydroflow、Hydroflow+)编译器与 VLDB 2025 的 Keep CALM and CRDT On(Laddad、Power 等)。

另一条线来自 INRIA / Nova LINCS 的 Shapiro、Preguiça、Baquero、Zawirski 2011 年的 Conflict-free Replicated Data Types:先识别满足半格(semilattice)结构的状态,再用”合并是 join”把多副本的冲突消灭在代数层面。十五年过去,CRDT 从论文里的 G-Counter、OR-Set 走到了 Yjs、Automerge 这种驱动真实多人协作编辑器的工业库,也走进了 Riak、Redis Enterprise、Azure Cosmos DB 这类商用数据库的功能清单。

两条线在 2024–2025 年开始显著地合流。原因很简单:CRDT 回答了”当你决定不协调时,数据结构该怎么设计”;CALM 回答了”什么时候你可以不协调”。前者是充分性的工程实现,后者是必要性的理论刻画。本文上半回到理论与综述层(CALM、单调性、CRDT 分类、Bloom/Hydro、VLDB 2025 新贡献);下半转到工程落地(Yjs、Automerge、Riak DT 的取舍,以及业务侧如何在设计评审时判断”这段逻辑能不能无协调”)。

版本说明 本文写作窗口为 2026 年 Q2:Yjs 13.x、Automerge 2.2.x、Riak 3.2(已归档)、Hydroflow 0.7 系列、Materialize 0.120 系列。论文以 CIDR 2010、PODC 2011、CACM 2020、VLDB 2023–2025 已公开版本为准;对无法从公开渠道确认的细节,本文标注”(待核实)“。


一、为什么又要谈 CALM 与 CRDT

1.1 协调是分布式系统里最贵的那一项开销

任何一个做过跨区域多写(multi-master)的团队都知道:机器故障不是最贵的,协调才是。Paxos、Raft、2PC、串行化快照隔离(SSI)——这些协议的可用性模型看起来很不同,但它们有一个共同的成本结构:

这也是 PACELC(Abadi 2012)能从 CAP 里把”正常运行期也要权衡 latency 与 consistency”这条细线单独拎出来的原因:即使没有分区,协调本身就是一笔 tax。

1.2 coordination-free 不是一种技术,而是一种判定

过去十年工业界在”能不能不协调”这个问题上做了很多局部尝试:因果一致性(Causal Consistency)、最终一致性(Eventual Consistency)、会话保证(Session Guarantees)、事务隔离级别的放松……但它们都是”给定某个一致性模型,怎么实现”,很少有人正面回答”给定这段业务逻辑,它是否有可能不协调地实现”。

CALM 定理把这个问题变成了一个可判定(decidable,针对 Datalog/Bloom 这样的声明式程序)的属性:逻辑是单调的 → 存在 coordination-free 的实现;不单调 → 必定需要协调,或者降级正确性

从”给实现找一致性模型”变成”给逻辑找可实现性”——这是一次视角翻转。

1.3 本文想回答的三件事

  1. 单调性究竟是什么,它和 CRDT 的半格结构是不是一回事?
  2. Hydro / Keep CALM and CRDT On 在 2025 年把这套理论推到了哪里?
  3. 工程上,面对一个业务需求(购物车、库存扣减、协作编辑、计数器),我们怎么判断”能不能无协调”,以及什么时候必须回到 Paxos?

1.4 读这篇之前可以准备的三点


二、CALM 定理再读

2.1 定义:单调性(monotonicity)

考虑一个以集合为输入、以集合为输出的程序 f。如果对任意输入 I₁ ⊆ I₂,都有 f(I₁) ⊆ f(I₂),则称 f 是单调的。

直观理解:新到的消息只会让答案”长”,不会让已有答案被撤回

注意”单调”是对输入集合的单调,不是对时间的单调。一条被”最终删除”的记录只要曾经参与了并集的产生,它的贡献就不会被撤回。

2.2 CALM 定理的陈述

Hellerstein 与 Alvaro 在 CACM 2020 的版本可以用一句话复述:

一个分布式、异步、可能乱序的分布式程序拥有 coordination-free、与集中式等价的实现,当且仅当它在声明式层面可被表达为一个单调的程序。

“当”方向是一个构造性证明:所有单调的 Datalog 程序都可以用 eventual delivery + local evaluation 执行,不需要跨节点的 barrier。 “仅当”方向是一个不可能性结果:非单调操作需要等待”所有输入到齐”这个事实本身,这一等就是协调。

2.3 为什么 “coordination-free” 不等于 “consistency-free”

CALM 定理里 coordination-free 特指”跨节点不需要协调”,它并不等于”没有任何一致性保证”。一个单调程序在 coordination-free 下仍然保证:

这两条是 CALM 定理真正有价值的部分:它告诉你”放弃协调”之后你还能保住什么。对比之下,“最终一致性”只保证收敛但不保证收敛到什么、也不保证 determinism。Alvaro 2011 CIDR Consistency Analysis in Bloom 里把这一点讲得很明白:不是所有最终一致都等价,单调性下的最终一致比一般最终一致强得多

2.4 单调性与 CRDT 半格的关系

CRDT 的核心是:状态 S 构成一个 join-semilattice (S, ⊔),合并函数 满足可交换、可结合、幂等(commutative, associative, idempotent,合称 CAI)。

这与 CALM 的单调性有严格的对应:CRDT 的状态更新是 CALM 意义下的单调函数,而 CRDT 的查询(读)常常是非单调的投影。例如一个 OR-Set 的状态更新单调,但如果你对它做 count(distinct),结果就不再单调——因为后续”删除事件”可能让计数回落。

这是一个被工程实践反复证伪的误解:“用了 CRDT 就不用协调了”。 正确的说法是:只要你的业务逻辑落在 CRDT 的单调子集里,就不用协调;一旦读路径要求非单调属性(确切计数、全局最小余额、互斥占用),协调就以某种形式回来了

2.5 协调的最小不可缩减成本

即使业务是非单调的,也不是每次操作都必须全局协调。CALM 的精细化版本(Ameloot 等 2013、PODC 2016 的 CRON 结果)给了两个可操作的减法:

  1. 局部协调足够:如果非单调的关键集中在单一分区(如”同一账户的并发扣款”),那么协调只发生在该分区内,其他并行工作可以无协调。
  2. 协调可以懒:可以在线无协调地处理,在读之前做一次协调(asymmetric read/write cost);或者反过来,写时协调、读时并行。

工程上这两条对应两个熟悉的模式:sharded serial zone(按键做单点序列化,其他一切并行)和 write-through consensus, read-anywhere(写入 Raft,读节点异步追 log)。

2.6 CALM 的边界:什么它不告诉你

CALM 告诉你”能不能 coordination-free 实现”,但不告诉你:

这是为什么后来工具链方向(Bloom / Hydro / Keep CALM and CRDT On)重要:光有定理不够,还要有能自动把”单调性”翻译成”具体实现”的工具。


三、CRDT 综述:从 Shapiro 2011 到 delta/pure-op

3.1 原始分类:state-based vs op-based

Shapiro 等 2011 的原论文给出两条路径:

两类在表达力上是等价的(有互相模拟的构造),工程上各有场景:CvRDT 适合离线优先、同步间隔长、消息可能丢的场景(Riak DT、Bucardo 风格同步);CmRDT 适合在线实时协作(Yjs、Automerge 的大部分算法)。

3.2 常见数据类型的单调结构

CRDT 半格 典型操作 陷阱
G-Counter (ℕⁿ, max per slot) inc 不能减
PN-Counter 两个 G-Counter 之差 inc / dec 读是非单调的
G-Set (2^U, ∪) add 不能删
2P-Set 两个 G-Set add / remove 删后不能再加
OR-Set 元素带唯一 tag add / remove 合并语义”add wins”
LWW-Register (V, 取最大时间戳) set 需要时钟;丢更新
MV-Register 元素带版本向量 set 读可能看到多版本
RGA / Logoot / YATA 带位置标识的序列 insert / delete 文本编辑专用,见 §3.4
JSON CRDT 嵌套 map/list/register 任意 JSON 路径 并发下 map/list 规则复杂

“陷阱”那一列是每个做过 CRDT 生产系统的团队都踩过的点。它们都指向同一件事:合并的单调性不等于读语义的直观性

3.3 delta-CRDT:工程化的 state-based

纯 state-based CRDT 的最大问题是”同步整份状态”不现实。Almeida、Shoker、Baquero 2016 的 Delta State Replicated Data Types 给了一个精巧的工程化路径:每次本地修改只产生一个 delta(也是半格上的一个元素),只在网络上传输这些 delta,但合并时仍然走 join。这相当于把 CvRDT 的”什么都可以丢”保留下来,同时把网络开销做到和 op-based 可比的水平。仓库里另一篇 delta-CRDT 专论 对此有独立展开。

3.4 RGA / Logoot / YATA:序列 CRDT 的三条路

文本编辑(协作 IDE、富文本)需要的是”序列 CRDT”——对同一个字符串并发插入/删除,最后所有副本看到一模一样的文本。主要有三条技术路线:

这三条线的共同困境是tombstone 的长期累积。Yjs 13 和 Automerge 2 都在做”历史压缩(garbage collection)“,但压缩必须保证副本间有共识——这又回到了协调。这是一个活跃的研究开放问题。

3.5 Pure op-based 与因果稳定性

Baquero、Almeida、Shoker 2014 提出的 Pure Op-Based CRDTs 把”传播什么”压缩到极致:只传原始操作(不含状态),依赖因果稳定性(causal stability)时才真正施加到状态上。这条线的代表实现是 Antidote DB、Legion、以及部分 AntidoteSQL 原型。

3.6 编程接口的分层:为什么工程师容易被”类型选错”困住

大多数 CRDT 库对外暴露的是数据结构OR-SetCounterMap),而不是代数层面(semilattice、commutative monoid)。这让业务开发者在选型时经常选错:

好的工程实践是在 CRDT 库之上再封一层业务语义,把”添加商品”、“移除标签”映射到具体的 CRDT 原语,并在文档里明确”这个操作的读一致性保证是什么”。这一步通常被忽略,直到线上出问题。


四、Bloom 语言、Hydro 与 VLDB 2025 新贡献

4.1 Bloom / BloomL:单调性作为一等公民

Alvaro、Conway、Hellerstein 2011 的 Bloom 把 Dedalus(时序扩展的 Datalog)变成一门编程语言,关键设计是类型系统能静态识别出每条规则的单调性——用半格类型 lmaxlminlboollsetlmap 声明数据,编译器可以告诉你”哪些规则需要协调点”。BloomL(SOCC 2012)把这一切延伸到任意用户自定义半格。

在 Bloom 之后,这条语言路线几乎停滞了十年;原因之一是它与主流工业语言(Go、Rust、Java)生态脱节,工程团队很难用 Bloom 写真实服务。

4.2 Hydro:把 CALM 搬到 Rust

Hellerstein 团队 2022 年之后把精力转向 Hydro:基于 Rust 的一组库与编译器(Hydroflow、Hydroflow+、Hydro Deploy),目标是把 Bloom 的静态单调性分析嵌入到一个现代工业级的数据流语言里。核心机制:

Hydro 还处在快速演化期(待核实最新版本号),但它是目前”把 CALM 做成能跑真实后端的工具链”最扎实的一次尝试。

4.3 Keep CALM and CRDT On(VLDB 2025)

Laddad、Power、Milano、Cheung、Crooks、Hellerstein 2024 年发表的 Keep CALM and CRDT On(VLDB 2025)把两条线直接焊接在一起。主要贡献(以官方论文摘要与作者在 CIDR / VLDB 现场的 talk 版本为准;部分实现细节待核实):

  1. CRDT 作为 Hydroflow 的一等类型。把半格作为类型系统里可以被静态检查的结构,用户写 Rust 代码时,编译器直接验证”这个类型的合并满足 CAI”。
  2. CALM 分析与 CRDT 组合的交叉优化。例如:如果一段子图是单调的,并且下游的消费者只做”读当前 join 值”,那么中间状态可以用 delta-CRDT 的 delta 流代替整份状态——这是 CALM 推出来的放宽。
  3. 局部非单调段的自动降级。对检测到的非单调子图,编译器能自动插入协调点(Raft 或 escrow),并给出”这段协调的代价在延迟预算里占多少”的静态估计。
  4. 与 Anna(Wu et al. SIGMOD 2018/2019)这类 coordination-free KV 的集成。把数据底座的半格与应用层的半格对齐,避免”数据库是 CRDT,应用层又手写协调”的重复税。

这篇论文最大的意义不在于任何单点创新,而是第一次把”单调性 → 可实现 → 有具体 CRDT 编码 → 可由编译器自动选取”这条链条,端到端在一个工业级工具链里打通。它让 CALM 从”理论告诉你边界”变成”工具告诉你怎么做”。

4.4 与其他同期工作的定位

把这几条线并在一起看,一个趋势很清楚:单调性正在从”一个性质”变成”一个架构接口”

4.5 一个最小心智模型

Keep CALM and CRDT On 时很容易被术语淹没。给一个最小心智模型帮助定位:

这个四层结构可以解释所有现代 coordination-free 研究工作的定位。Anna 强调最底层,Bloom/Hydro 强调中层与上层的衔接,VLDB 2025 这篇把四层串起来。Materialize / RisingWave / Feldera 则是 DBSP 版本的类似四层架构(见 下一篇)。


五、Yjs、Automerge、Riak DT 的工程现状

5.1 Yjs 13:协作编辑器事实标准

Yjs 使用 YATA 算法做序列 CRDT,加上 Y.MapY.ArrayY.TextY.XmlFragment 等顶层类型,是今天协作编辑器(如 Notion 早期、JupyterLab RTC、TipTap、BlockSuite)的事实标准。工程亮点:

踩坑点: - 历史压缩。Yjs 默认不主动丢弃 tombstone,长期协作文档会让状态单调增长。社区方案 y-redisy-leveldb 各有自己的 snapshot 策略,但都不保证所有客户端能无损裁剪。 - 字符串合并的”意外顺序”。两个客户端同时在相邻位置插入时,YATA 决定的最终顺序在代数上是良定义的,但对用户而言未必是最”像预期的”的顺序——这是 CRDT 领域无法绕开的问题:代数正确 ≠ 用户心理模型正确。 - 并发光标跳动。editor 内部使用 position anchors 追踪光标位置;远端 update 到达时 anchors 需要重新解算,用户经常看到”光标短暂跳到别处”。现代 editor(Lexical、BlockSuite)都有专门的 anchor 校准层。

5.2 Automerge 2:朝着”通用 JSON CRDT”

Automerge(Kleppmann, Ink & Switch)和 Yjs 的目标重叠但定位不同:Automerge 更像”一个通用的 JSON CRDT”——支持任意嵌套的 map/list/counter/text,并强调 local-first software 的完整栈(Ink & Switch 的 Peritext、Upwelling、Patchwork 都是在它上面建的)。

Automerge 2 最重要的工程变化是从”TypeScript/JS 实现”切换到 Rust 核心 + 各语言 binding(automerge-rs)。这意味着:

Automerge 的代数更接近 Kleppmann 2017 A Conflict-Free Replicated JSON Datatype 的”tombstone + version vector”模型,对并发的 map 键冲突、list 并发插入都有明确的合并语义(但仍然有”user-surprising”的边界情形)。

Ink & Switch 在 Peritext(2022)里提出了一个针对富文本格式(bold、italic、link)的扩展 CRDT——格式本身也要能并发合并。这类”格式 CRDT” 问题比字符序列复杂:一段文本的并发 bold 与并发 italic 要能共存,而并发”删除并格式化”又要有明确结果。Peritext 给出了一个当前最成熟的方案,但它仍然是研究课题。

5.3 Riak DT 与商用 KV 的 CRDT 功能

Basho 的 Riak 2013 开始在 KV 层提供内置 CRDT(G-Counter、PN-Counter、OR-Set、Map、Register),论文基础是 INRIA 的工作。Riak 项目 2017 年后逐步归档,但它的 CRDT 设计是后续许多系统的参照:

5.4 工程口径的统一对照

维度 Yjs Automerge Riak DT
语言内核 TS/JS(部分 WASM 化) Rust(binding 多语言) Erlang
主场景 实时协作编辑 local-first 应用 + 协作 分布式 KV
序列算法 YATA RGA 变体 无(KV 不管序列)
历史 GC 不完整,provider 侧处理 部分(actor 压缩) 不适用
网络模型 CmRDT + 因果 CmRDT + 因果 CvRDT
打包尺寸 极小(<50KB JS) 中等(WASM ~MB) 服务端组件

5.5 性能边界:把 CRDT 推到极限会发生什么

生产里把 CRDT 库推到边界的典型场景:

这些边界不是 CRDT 算法本身的缺陷,而是”把代数正确的结构推到工程尺度”时的实际代价。设计评审时要明确文档规模上限离线时长上限,超过就要切回”文档拆分”或”回到协调”的策略。


六、业务侧如何判断”能不能无协调”

6.1 一张判定清单

在真实设计评审时,我们按下面这张清单走一遍,比直接争论 “用不用 Raft” 更有效:

  1. 写语义是否单调?也就是说,“新加一条记录”是否只会扩大结果集?如果出现”减、删除、覆盖、互斥占用”,则非单调。
  2. 读语义是否非单调?哪怕写是单调的(如 OR-Set),读出”精确计数”或”是否存在且唯一”都会让整体非单调。
  3. 非单调段是否落在单一分区?如果是同一账户、同一实体上的非单调操作,协调只需要在这个分区内做(例如 per-key Raft group),其余依然可以并行。
  4. 业务能否接受 escrow 或预留?库存扣减的经典技巧:把 1000 件库存切成 10 份各 100 件 escrow 到不同分区,每份内部无协调地扣,份之间偶尔再平衡。
  5. 读是否能接受”最终收敛 + 有界 staleness”?如果业务读侧可以接受有限过时(如仪表盘、排行榜、feed),CRDT / CALM 的代价最低。
  6. 是否存在”全局判定”(如唯一用户名、转账原子性)?这一类几乎肯定要协调,区别只在于协调是落在事务协议、leader 抢占、还是外部锁服务。

6.2 三个常见案例

购物车。加商品是单调(add);减商品在同一购物车内可以做 OR-Set 语义;结算时的”是否库存足够” 是非单调,放在结算事务里单独做。加购物车的写路径完全可以 CRDT 化(Riak、DynamoDB multi-region 风格),结算走 OCC/SI 事务。

协作编辑。文本 insert/delete 的合并是 RGA/YATA;但”文档是否被导出、版本号是否单调递增、是否被锁定只读”这些元操作是非单调的,需要一个小 leader(通常是文档服务)来做序列化。Yjs 的生产部署中,正文走 coordination-free,元数据走传统数据库事务。

库存扣减。纯 CRDT 不适合(“不能低于 0” 是非单调约束)。工业界标准解法是 escrow:把库存切成多个 reservation 块分布到多个分区,每个块内部的扣减单调,块之间偶发协调(rebalance / refill)。只有在所有块都见底时退化成全局协调。详见仓库的 分布式事务专题 相关文章。

6.3 何时必须回到 Paxos/Raft

三种情况下”无协调”几乎一定不成立:

  1. 严格单调递增的外部 ID(如数据库事务 ID、支付流水号的严格序);
  2. 全局互斥资源(主备切换、领导者选举、分布式锁);
  3. 基于”当前值”判断的副作用(“余额足够则扣款并发短信”——副作用的 at-most-once 需要协调)。

这些场景下,与其勉强做 CRDT,不如直接走 Raft/Paxos。仓库里 Raft 深入Paxos共识工程实践 这三篇有具体工程讨论。

6.4 评审时的两个反模式

6.5 一个完整案例:多区域购物车

把前面的判定清单落到一个具体案例上。假设我们做一个跨区域(US / EU / APAC)的电商购物车服务,目标是:“用户在任一区域的任一设备上都能看到自己所有改动,最终一致;不接受丢购物车项。”

步骤 1:拆出可单调的子问题。“加商品”和”删商品”用 OR-Set:每次 add 给商品 ID 附一个 unique tag;每次 remove 记录要删的 tag 集合。合并在半格上做,完全 coordination-free。

步骤 2:识别非单调读。“购物车当前总金额”是对 OR-Set 的非单调聚合。但我们不需要它全局一致——总金额在 UI 上允许 “实时更新但短暂跳动”,实现上在每个区域本地聚合即可。

步骤 3:结算时的协调点。下单时需要”确认总金额 + 锁库存 + 扣支付”。这一刻必须回到协调——走 OCC/SI 事务,就近选一个区域做结算 leader,其他区域把该购物车临时”冻结”(通过一个 LWW 状态 flag;冲突概率低,用 LWW 可接受)。

步骤 4:失败与回退。如果结算失败,把 flag 清掉,CRDT 状态继续允许修改。整个流程里只有结算一小段协调窗口,其余时间完全无协调。

为什么有效。这正是 §2.5 的 “sharded serial zone” 模式:非单调只发生在单一购物车 ID 上,协调局部化;其他购物车完全并行。


七、把 CRDT 嵌进已有服务的三种姿势

7.1 姿势一:把 CRDT 放在应用层,数据库只当 blob 存储

这是 Yjs、Automerge 在多数生产部署下被使用的方式:业务服务持有 Y.DocAutomerge.Doc 实例,把编码后的二进制 update 写到任意一个 KV(PostgreSQL、Redis、对象存储)。数据库只负责”拿得到、拿得全”,不解析、不参与合并。

这是工业界最常见的模式。它背后隐含的判断是:“我不信任数据库内置的 CRDT;我只信任我 SDK 版本里的 CRDT 实现。”

7.2 姿势二:数据库内置 CRDT 类型

Redis Enterprise CRDB、Riak DT、Azure Cosmos DB 的 multi-master 属于这一类。数据库引擎知道某张表/某个 key 是一个 PN-Counter / OR-Set / LWW-Register,合并在引擎内部完成。

实践建议:这种姿势适合有明确 CRDT 类型、且跨区域多写流量确实大的场景(全球化计数、排行榜、购物车增减)。其他场景不如姿势一。

7.3 姿势三:数据流中间件承担 CRDT 合并

这是 Hydro / Anna / Bloom 这条学术路线想推进的方向:把 CRDT 合并下沉到数据流/KV 中间件,应用端只写一个数据流程序(可能是 SQL、Bloom、Hydroflow)。Materialize、Noria、Anna 都在这条谱系里。

7.4 选姿势的三个判断

  1. 我的 CRDT 会用在几种客户端?多客户端(移动 + Web + 服务端)→ 姿势一(共享 SDK)更可控;
  2. 跨区域多写的流量比例?占大头 → 姿势二(数据库内置)省最多;
  3. 业务逻辑的 CRDT 复杂度?纯计数/集合 → 姿势二够用;嵌套/富文本 → 只有姿势一能撑住。

八、一个常见的误用:LWW 作为万能默认

8.1 LWW 看起来省事,实际上是”静默丢写”

LWW(Last-Write-Wins)寄存器只要求有一个全序时间戳,合并就是”取最大时间戳那个值”。工程上它是最便宜的 CRDT:Cassandra 的 cell timestamp、DynamoDB 的 last-writer-wins、Riak 的 allow_mult=false,本质都是 LWW。

它的代价容易被低估:并发写里,只有一个幸存;其他”被丢了”的写没有任何告警。一个被 LWW “吃掉”的订单修改,在日志里和网络抖动无法区分。

8.2 什么时候 LWW 可以接受

8.3 什么时候必须换成更强的 CRDT

8.4 兜底:让冲突变得可见

即便选了强 CRDT,“合并结果不符合用户预期”的情形仍会出现(§5.1 提到的 YATA 例子)。两个务必提供的工程兜底:

这是”代数正确”与”用户正确”之间不可绕开的那层胶水。


九、因果一致性、会话保证与 CRDT 的关系

CRDT 经常和因果一致性(Causal Consistency, CC)被放在一起讲,但它们回答的问题不同:

CC 的常见实现用版本向量(Version Vector)dotted version vector 来追因果;CRDT 可以直接把因果信息编进类型内部(比如 OR-Set 里元素的 tag)。工程上两者是互补的:

仓库里的 会话一致性保证一致性模型全家谱 有对 CC 的独立讨论;本文不在此展开。

9.1 与 CALM 的闭环

一个常被忽略的观察:CC + 单调性 = coordination-free。如果你的系统只走因果可见、且所有操作单调,那么不需要任何全局协调,你就拿到了一个正确的 coordination-free 系统。Bloom 的类型系统、Anna 的 lattice 合并、Hydro 的 subgraph 分析本质上都在帮你维持这个闭环。反过来,只要有一个非单调点(比如”一次 exactly-once 通知”),闭环就破了,要么协调、要么降级。


十、开放问题与小结

10.1 开放问题

10.2 一段话总结

CALM 定理告诉你什么时候可以不协调;CRDT 告诉你如果决定不协调,状态和合并该如何设计;Hydro 与 Keep CALM and CRDT On 把这两者焊进同一个工具链;Yjs、Automerge、Riak DT 则给出了十五年的工程化证据,证明”coordination-free 可落地、但永远有一个非单调的外层需要回到协调”。

下一个十年值得观察的是:当数据库、消息系统、前端应用都开始把”半格类型”当成公共接口时,“协调”是否会从”系统默认”退化成”偶尔的显式选择”。

10.3 一张可贴在墙上的速查

问题 快速答案
“这个操作要协调吗?” 单调 → 不必;非单调 → 必须(或降级)
“我要挑哪种 CRDT?” 纯增长 → G-Set/G-Counter;有删 → OR-Set/PN-Counter;有序 → RGA/YATA;嵌套 → JSON CRDT
“LWW 能不能用?” 只在”新写一定对”的语义下;否则换 OR-Set/PN-Counter
“CRDT 换 Raft 的临界在哪?” 出现”唯一性、互斥、精确计数、exactly-once 副作用” 就回到 Raft
“评审里该问什么?” 写单调吗?读单调吗?非单调能否单分区隔离?能否 escrow?能否接受有限 staleness?

参考文献

  1. Hellerstein J. M. The Declarative Imperative: Experiences and Conjectures in Distributed Logic. CIDR 2010. https://www.cidrdb.org/cidr2011/Papers/CIDR11_Paper1.pdf
  2. Hellerstein J. M., Alvaro P. Keeping CALM: When Distributed Consistency is Easy. CACM, February 2020. https://arxiv.org/abs/1901.01930
  3. Shapiro M., Preguiça N., Baquero C., Zawirski M. Conflict-Free Replicated Data Types. SSS 2011 / INRIA RR-7687. https://hal.inria.fr/inria-00609399
  4. Shapiro M. et al. A Comprehensive Study of Convergent and Commutative Replicated Data Types. INRIA RR-7506, 2011.
  5. Almeida P. S., Shoker A., Baquero C. Delta State Replicated Data Types. Journal of Parallel and Distributed Computing, 2018.
  6. Alvaro P., Conway N., Hellerstein J. M., Marczak W. R. Consistency Analysis in Bloom: a CALM and Collected Approach. CIDR 2011.
  7. Conway N., Marczak W. R., Alvaro P., Hellerstein J. M., Maier D. Logic and Lattices for Distributed Programming. SoCC 2012. (BloomL)
  8. Ameloot T. J., Neven F., Van den Bussche J. Relational Transducers for Declarative Networking. JACM 2013. (CALM 证明)
  9. Laddad S., Power C., Milano M., Cheung A., Crooks N., Hellerstein J. M. Keep CALM and CRDT On. VLDB 2025. (作者与题目以 VLDB 2025 program 为准;部分实现细节待核实)
  10. Wu C., Faleiro J. M., Lin Y., Hellerstein J. M. Anna: A KVS For Any Scale. ICDE 2018 / SIGMOD 2019.
  11. Kleppmann M., Beresford A. R. A Conflict-Free Replicated JSON Datatype. IEEE TPDS 2017. https://arxiv.org/abs/1608.03960
  12. Nicolaescu P., Jahns K., Derntl M., Klamma R. YATA: Yet Another Transformation Approach for Real-time Collaboration. ICWE 2016. (Yjs 基础算法)
  13. Roh H.-G., Jeon M., Kim J.-S., Lee J. Replicated Abstract Data Types: Building Blocks for Collaborative Applications. JPDC 2011. (RGA)
  14. Weiss S., Urso P., Molli P. Logoot-Undo: Distributed Collaborative Editing System on P2P Networks. IEEE TPDS 2010.
  15. Baquero C., Almeida P. S., Shoker A. Making Operation-Based CRDTs Operation-Based. DAIS 2014. (pure op-based)
  16. Yjs 官方文档. https://docs.yjs.dev/
  17. Automerge 官方文档. https://automerge.org/docs/
  18. Hydro 项目主页. https://hydro.run/
  19. Abadi D. Consistency Tradeoffs in Modern Distributed Database System Design: CAP is Only Part of the Story. IEEE Computer, 2012. (PACELC)

上一篇【数据库研究前沿】加密数据库:FHE、PIR 与可搜索加密的工程边界

下一篇【数据库研究前沿】流批一体与增量视图:Materialize、RisingWave、Feldera 的 DBSP 理论

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .