跳转到内容

Aeron Cluster 与 Raft 共识

Aeron Cluster 是面向有状态、事件驱动应用的容错集群。它以微秒级延迟提供内存中状态,底层有一份 Raft 复制的日志作为支撑,确保你永远不会丢失任何已提交的事件。本页介绍其设计原则、让 Raft 得以运转的 两个 RPC、Aeron 在其之上叠加的改进,以及让整套机制对撮合引擎而言足够安全的五项安全保证。

至于字节级的内部细节——日志布局、term 文件、archive 录制——请参阅 The Aeron Files。本页是运维者的心智模型,而非线路(wire)格式。

Aeron Cluster 构建在 Aeron Transport 之上,而非 TCP。这一选择决定了其余的整体设计。

  • 极高吞吐与极低延迟 —— 构建在 Aeron Transport 之上,而非 TCP。
  • 状态完全保存在内存中 —— 热路径上没有数据库。
  • 输入事件写入持久化存储 —— 通过 Aeron Archive 实现,用于节点恢复。
  • 复制到其他节点与站点 —— 基于 Raft 的共识以保证一致性。
  • 单一集群上承载多个服务 —— 在多个服务间共享共识基础设施。

各层的堆叠方式如下:

所有状态都驻留在内存中。持久化日志(Archive)只为恢复而存在。这正是实现微秒级处理的关键:热路径上 没有磁盘 I/O,没有数据库查询,也没有对外部系统的网络调用。结果会直接体现在你的延迟剖面上——p50 和 p99 保持很低,因为请求无需触及磁盘或远程服务即可产生响应。

Raft 共识只用到两个 RPC。这就是整个协议的全部接口面。

  • 由候选者(candidate)发起,在 leader 选举期间收集选票。
  • 节点转入候选者状态,递增其 term,给自己投票,并向所有其他节点发送 RequestVote。
  • 其他节点在候选者的日志至少与自身一样新(up-to-date)时,才会投出选票。
  • 由 leader 发起,用于两个目的:
    • 日志复制 —— 向 follower 发送新的日志条目。
    • 心跳(Heartbeat) —— 空的 AppendEntries,用于维持领导权(防止 follower 发起选举)。

为什么只有两个?这种简洁是刻意为之的。消息类型越少,就意味着边界情况越少、bug 越少,形式化验证也越 容易。Raft 中的一切要么是”谁应当成为 leader?“(RequestVote),要么是”leader 这样说” (AppendEntries)。

Aeron Cluster 用三个基本构件来实现 Raft,并在原始论文之上做了若干改进。

构建在以下之上:

  • Aeron Transport —— 用于节点间通信(UDP,而非 TCP)。
  • Aeron Archive —— 用于持久化日志存储。
  • Consensus Module —— Aeron 的 Raft 实现。

1. 选举前的 canvass 阶段。 在节点成为候选者并发起正式选举之前,它会先向其他节点进行试探 (canvass),以检查选举是否会成功。这避免了会扰乱集群的无谓选举——一个节点不会发起一场它明知会输掉 的选举。

2. 节点间的并行复制。 leader 同时向所有 follower 发送 AppendEntries,而非逐个串行发送。因此,提交 延迟受限于法定多数(quorum)中最慢的那个节点,而不是所有节点之和。

3. 复制过程中的自然批处理。 当多个日志条目可用时,会被批量打包进单个 AppendEntries 消息。这减少了 网络往返、提升了吞吐,且不引入人为的批处理延迟——这是一项对延迟毫无代价的吞吐收益。

Raft 的正确性建立在五项保证之上。它们共同确保集群永远不会出现分歧(diverge)。

在任一给定 term 内,最多只能选出一个 leader。

这可以防止脑裂(split-brain)——你绝不会出现两个节点都认为自己是同一 term 编号下的 leader 的情况。它 通过要求获得多数票来强制保证。

2. Leader 仅追加(Leader Append-Only)

Section titled “2. Leader 仅追加(Leader Append-Only)”

leader 绝不覆盖或删除其日志中已有的条目。

leader 只追加新条目;它从不修改历史。这使得 leader 的日志成为一个单调增长、不可变的序列——这对一致性 至关重要。

3. 日志条目一致性(日志匹配,Log Matching)

Section titled “3. 日志条目一致性(日志匹配,Log Matching)”

如果两份日志中存在一个具有相同 index 和 term 的条目,那么这两份日志在该 index 之前的所有条目都完全 相同。

这是让 Raft 得以运转的归纳性质:如果两个节点在条目 (index=42, term=5) 上达成一致,那么它们在条目 1–41 上也必然一致。它通过 leader 在每个 AppendEntries 中都包含前一条目的 index 和 term 来强制保证 ——follower 会拒绝不匹配的条目。

4. Leader 完整性(Leader Completeness)

Section titled “4. Leader 完整性(Leader Completeness)”

如果某个日志条目在某一 term 内被提交,那么该条目将存在于所有更高编号 term 的 leader 的日志中。

一旦某个条目被提交(已复制到多数节点),它就永远不会丢失——每一个未来的 leader 都必然拥有它。它通过 投票规则来强制保证:节点不会把票投给日志完整度低于自身的候选者。

5. 状态机安全性(State Machine Safety)

Section titled “5. 状态机安全性(State Machine Safety)”

如果某台服务器已将某一 index 处的日志条目应用到其状态机,那么其他任何服务器都绝不会在同一 index 处 应用一个不同的日志条目。

这是终极的一致性保证:所有节点都将相同的操作序列应用到各自的状态机上。结合确定性执行,每个节点都会 收敛到完全相同的状态。

保证它确保了什么
Election Safety(选举安全性)每个 term 只有一个 leader
Leader Append-Only(Leader 仅追加)leader 从不重写历史
Log Matching(日志匹配)对单个条目的一致即对所有先前条目的一致
Leader Completeness(Leader 完整性)已提交的条目在 leader 更替后依然存在
State Machine Safety(状态机安全性)所有节点以相同顺序应用相同的操作