@@ -44,15 +44,15 @@ transaction 定序(Sequencer)层:Calvin 的所有分区的 Sequencer 进
44
44
45
45
## Transaction 流程分解:预定序、复制、执行
46
46
47
- Calvin 的 transaction 执行流程分为三个阶段:** Transaction 预定序** 、 ** 日志复制** 和 ** Transaction 执行** 。
47
+ Calvin 的 transaction 执行流程分为三个阶段: ** Transaction 预定序** 、 ** 日志复制** 和 ** Transaction 执行** 。
48
48
49
- - ** Transaction 预定序** :客户端将 transaction 请求(通常是存储过程形式)提交给系统。各分区的 Sequencer 接收 transaction 请求,并将其按照当前 epoch 进行归集。每个 transaction 需要声明其读写集合。在一个 10ms 的 epoch 内,所有到达的 transaction 请求都会被暂存。Epoch 结束时,各 Sequencer 对收到的 transaction 赋予序号并打包。
49
+ - ** Transaction 预定序** :客户端将 transaction 请求(通常是存储过程形式)提交给系统。各分区的 Sequencer 接收 transaction 请求,并将其按照当前 epoch 进行归集。每个 transaction 需要声明其读写集合。在一个 10ms 的 epoch 内,所有到达的 transaction 请求都会被暂存。Epoch 结束时,各 Sequencer 对收到的 transaction 赋予序号并打包。
50
50
51
- - ** Transaction 日志复制** :每个分区内部通过 Paxos 共识将该 transaction 日志复制到分区的各个副本节点。这确保即使某个副本故障,其他副本也有相同的 transaction 输入日志。一旦某分区的 transaction 在其复制组内被确定,该分区的 Sequencer 就会向本地和其他分区的 Scheduler 发送该 transaction 的信息。所有 Scheduler 收集来自所有分区的 transaction 后,根据约定规则将不同分区的 transaction 全局排序,得到一致的全局 transaction 序列。
51
+ - ** Transaction 日志复制** :每个分区内部通过 Paxos 共识将该 transaction 日志复制到分区的各个副本节点。这确保即使某个副本故障,其他副本也有相同的 transaction 输入日志。一旦某分区的 transaction 在其复制组内被确定,该分区的 Sequencer 就会向本地和其他分区的 Scheduler 发送该 transaction 的信息。所有 Scheduler 收集来自所有分区的 transaction 后,根据约定规则将不同分区的 transaction 全局排序,得到一致的全局 transaction 序列。
52
52
53
- - ** Transaction 执行与调度** :各节点的 Scheduler 面对同样的全局 transaction 序列开始执行调度。Calvin 采用确定性两阶段锁定协议:系统按全局顺序依次为 transaction 的所有读写项请求锁。由于全局日志顺序已确定,如果两个 transaction 涉及同一数据项,先出现在日志中的 transaction 其锁请求会先被调度,从而保证锁获取顺序与全局 transaction 顺序一致。这种机制避免了死锁,且不需要回滚重试。
53
+ - ** Transaction 执行与调度** :各节点的 Scheduler 面对同样的全局 transaction 序列开始执行调度。Calvin 采用确定性两阶段锁定协议:系统按全局顺序依次为 transaction 的所有读写项请求锁。由于全局日志顺序已确定,如果两个 transaction 涉及同一数据项,先出现在日志中的 transaction 其锁请求会先被调度,从而保证锁获取顺序与全局 transaction 顺序一致。这种机制避免了死锁,且不需要回滚重试。
54
54
55
- - ** Transaction 执行** :获得所需锁后, transaction 会被交给工作线程执行。
55
+ - ** Transaction 执行** :获得所需锁后, transaction 会被交给工作线程执行。
56
56
57
57
Calvin 预先定序,使执行阶段有序,无需跨节点协调,从而避免了两阶段提交的复杂交互;若节点故障, transaction 请求已在全局日志中,其他副本可继续执行。
58
58
@@ -86,23 +86,23 @@ Calvin 的架构描述并不很直观, 换个以共识为中心的视角, 对 Ca
86
86
87
87
Calvin 的设计与传统的 “2PC + Paxos” 分布式 transaction 处理方案截然不同,下面从几个方面进行比较:
88
88
89
- - ** transaction 定序方式** :传统分布式数据库(例如早期的 NewSQL 系统或 Spanner 等)通常将数据按 Partition 复制,每个 Partition 内部通过 Paxos/Raft 保证强一致复制,但跨 Partition 的 transaction 需要使用两阶段提交 (2PC) 来协调顺序和原子性。 在这种模式下,每笔跨 Partition transaction 在执行完业务逻辑后,必须由协调者发起投票请求各 Partition 准备提交,然后再发出提交指令。这实际形成了一个** 逐 transaction 的共识** 过程:各 Partition 就该 transaction 是否提交达成一致。这种做法的代价是高昂的—— transaction 在整个 2PC 过程中必须持有锁不释放,直到所有 Partition 都确认提交,导致** 锁的持有时间远超实际执行时间** ,严重降低并发性能 。特别是当 transaction 需要同步复制(Paxos)数据到多个副本时, transaction 的** 争用窗口** 还包括了复制的网络延迟 。
89
+ - ** transaction 定序方式** :传统分布式数据库(例如早期的 NewSQL 系统或 Spanner 等)通常将数据按 Partition 复制,每个 Partition 内部通过 Paxos/Raft 保证强一致复制,但跨 Partition 的 transaction 需要使用两阶段提交 (2PC) 来协调顺序和原子性。 在这种模式下,每笔跨 Partition transaction 在执行完业务逻辑后,必须由协调者发起投票请求各 Partition 准备提交,然后再发出提交指令。这实际形成了一个 ** 逐 transaction 的共识** 过程:各 Partition 就该 transaction 是否提交达成一致。这种做法的代价是高昂的—— transaction 在整个 2PC 过程中必须持有锁不释放,直到所有 Partition 都确认提交,导致 ** 锁的持有时间远超实际执行时间** ,严重降低并发性能 。特别是当 transaction 需要同步复制(Paxos)数据到多个副本时, transaction 的 ** 争用窗口** 还包括了复制的网络延迟 。
90
90
91
- - **Calvin 的无 2PC 创新**:Calvin 最大的创新在于**通过全局确定性预定序彻底移除了 2PC 提交协议**。在 Calvin 中, transaction 在执行之前就已经被放入全局日志并确定了顺序,事实上**提交的决议在调度阶段已完成**——一旦 transaction 出现在全局序列中,就相当于各 Partition 已经“同意”了其提交。 因此,Calvin 不再需要 transaction 结束后的两阶段协调,也无需在执行后再运行 Paxos 来提交结果。各 Partition 只要按照既定顺序执行 transaction 并应用更新即可。当一个 transaction 涉及多个 Partition 时,Calvin 通过在所有相关 Partition 预先记录该 transaction (作为输入日志的一部分)实现原子性:要么所有 Partition 都按序执行它,要么(在故障情况下)都可以通过日志重放来补上它,从而保证**跨 Partition transaction 要么整体提交、要么整体不生效**。这种方式等价于一种**状态机复制**:全局 transaction 日志作为状态机的指令序列,每个 Partition 都应用相同序列的指令,确保最终一致。
91
+ - **Calvin 的无 2PC 创新** :Calvin 最大的创新在于 **通过全局确定性预定序彻底移除了 2PC 提交协议** 。在 Calvin 中, transaction 在执行之前就已经被放入全局日志并确定了顺序,事实上 **提交的决议在调度阶段已完成** ——一旦 transaction 出现在全局序列中,就相当于各 Partition 已经“同意”了其提交。 因此,Calvin 不再需要 transaction 结束后的两阶段协调,也无需在执行后再运行 Paxos 来提交结果。各 Partition 只要按照既定顺序执行 transaction 并应用更新即可。当一个 transaction 涉及多个 Partition 时,Calvin 通过在所有相关 Partition 预先记录该 transaction (作为输入日志的一部分)实现原子性:要么所有 Partition 都按序执行它,要么(在故障情况下)都可以通过日志重放来补上它,从而保证 **跨 Partition transaction 要么整体提交、要么整体不生效** 。这种方式等价于一种 **状态机复制** :全局 transaction 日志作为状态机的指令序列,每个 Partition 都应用相同序列的指令,确保最终一致。
92
92
93
- - **性能与开销对比**:传统 2PC 协议在 Partition 数目增加和跨 Partition transaction 频繁时性能会急剧下降,因为每个 transaction 的提交都触发跨所有参与 Partition 的同步交互。而 Calvin 将系统的同步点固定为每个 epoch 一次,不论该 epoch 内有多少 transaction ,**只需一次全局批处理通信来确定顺序** 。这样做显著降低了消息交互频率,提高了吞吐量。研究表明,在 10ms 批次下,Calvin 每秒可处理 **50 万+ transaction**,远高于典型互联网应用所需 。相比之下,传统方案即使单 Partition transaction 可以较快提交,但一旦遇到多 Partition transaction ,其 2PC 延迟和复杂性都会降低整体吞吐。此外,Calvin 将数据复制的开销前置融合进了定序阶段(复制 transaction 输入而非执行结果),这避免了在 transaction 提交时再执行一遍 Paxos,同样减少了额外的等待。综上,Calvin 用较大的**计划开销**(批处理定序)换取了执行阶段的**轻量快速**,适合高负载下涉及多 Partition 的 transaction 场景。
93
+ - **性能与开销对比** :传统 2PC 协议在 Partition 数目增加和跨 Partition transaction 频繁时性能会急剧下降,因为每个 transaction 的提交都触发跨所有参与 Partition 的同步交互。而 Calvin 将系统的同步点固定为每个 epoch 一次,不论该 epoch 内有多少 transaction , **只需一次全局批处理通信来确定顺序** 。这样做显著降低了消息交互频率,提高了吞吐量。研究表明,在 10ms 批次下,Calvin 每秒可处理 **50 万+ transaction** ,远高于典型互联网应用所需 。相比之下,传统方案即使单 Partition transaction 可以较快提交,但一旦遇到多 Partition transaction ,其 2PC 延迟和复杂性都会降低整体吞吐。此外,Calvin 将数据复制的开销前置融合进了定序阶段(复制 transaction 输入而非执行结果),这避免了在 transaction 提交时再执行一遍 Paxos,同样减少了额外的等待。综上,Calvin 用较大的 **计划开销** (批处理定序)换取了执行阶段的 **轻量快速** ,适合高负载下涉及多 Partition 的 transaction 场景。
94
94
95
- - ** 复杂性与应用限制** :Calvin 为了实现确定性,需要 transaction 在提交时就声明所有将访问的数据,这对应用提出了要求。传统 2PC 可以支持事中计算后决定访问哪些数据,而 Calvin 更适合** 预定义的 transaction (Stored Procedure)** 模型。在这一点上,是用交易弹性换取性能的权衡。另外,Calvin 的全局顺序使得哪怕是只访问单 Partition 的数据,也必须经过定序层处理,这相比本地直接提交稍有额外开销;而传统方案下单 Partition transaction 可以直接在本地提交(不经过全局协议)。因此,当绝大多数 transaction 都是单 Partition 且几乎不存在分布式 transaction 时,Calvin 的优势不明显甚至可能不如简单的单 Partition 提交+弱同步方案。不过,在需要强一致性且存在大量跨 Partition 操作的系统中,Calvin 提供了一种极具创新性的解决方案,使分布式 transaction 性能达到实用水平。
95
+ - ** 复杂性与应用限制** :Calvin 为了实现确定性,需要 transaction 在提交时就声明所有将访问的数据,这对应用提出了要求。传统 2PC 可以支持事中计算后决定访问哪些数据,而 Calvin 更适合 ** 预定义的 transaction (Stored Procedure)** 模型。在这一点上,是用交易弹性换取性能的权衡。另外,Calvin 的全局顺序使得哪怕是只访问单 Partition 的数据,也必须经过定序层处理,这相比本地直接提交稍有额外开销;而传统方案下单 Partition transaction 可以直接在本地提交(不经过全局协议)。因此,当绝大多数 transaction 都是单 Partition 且几乎不存在分布式 transaction 时,Calvin 的优势不明显甚至可能不如简单的单 Partition 提交+弱同步方案。不过,在需要强一致性且存在大量跨 Partition 操作的系统中,Calvin 提供了一种极具创新性的解决方案,使分布式 transaction 性能达到实用水平。
96
96
97
97
## Calvin 无法完全替代 2PC 的原因
98
98
99
99
Calvin 虽然高效,但并不能在所有场景下替代 2PC,主要有以下限制:
100
100
101
- 1 . ** 等待所有 Partition 的约束** :Calvin 要求 Scheduler 必须收到所有 Partition 在当前 epoch 的完整 Transaction 列表后才能开始执行。相比之下,2PC 更灵活,它通过一次通信(phase-1 锁定阶段)就能确定 transaction 需要等待哪些特定的 Partition,而不必等待所有 Partition 。
101
+ 1 . ** 等待所有 Partition 的约束** :Calvin 要求 Scheduler 必须收到所有 Partition 在当前 epoch 的完整 Transaction 列表后才能开始执行。相比之下,2PC 更灵活,它通过一次通信(phase-1 锁定阶段)就能确定 transaction 需要等待哪些特定的 Partition,而不必等待所有 Partition 。
102
102
103
- 1 . ** 通信模式差异** :Calvin 通过牺牲一定的灵活性,换取了省去一次 RPC 通信的效率,使整个 transaction 提交过程能够无阻塞执行。
103
+ 1 . ** 通信模式差异** :Calvin 通过牺牲一定的灵活性,换取了省去一次 RPC 通信的效率,使整个 transaction 提交过程能够无阻塞执行。
104
104
105
- 1 . ** Calvin 的系统限制** :
105
+ 1 . ** Calvin 的系统限制** :
106
106
107
107
- 每个 epoch 必须与所有 Partition 通信,即使某些 Partition 与当前 transaction 无关.
108
108
- 系统拓扑变更复杂:无法直接增删 Partition。若要变更 Partition 结构,需要在所有 Partition 之间达成共识,防止增加新 Partition 时遗漏等待对象,或删除 Partition 时等待不存在的节点.
0 commit comments