客户端与集群的通信流程
客户端从不直接与你的服务通信,它们只与集群通信。这种间接性正是关键所在——它把一连串客户端请求,在你的业务逻辑读到任何一个字节之前,转化为一份有序、已复制、持久化的日志。
本页将端到端地追踪一条消息的完整路径:建立连接、重定向到 leader、ingress、consensus、服务执行、egress。弄清每一跳发生在哪里,你就能精确知道 p50、p99 和吞吐量究竟在哪里被赢得或失去。
一条客户端消息会经历四个阶段。每个阶段都有各自的职责,也都会带来你可以推理分析的延迟。
- 客户端连接到任意集群节点——并可能被重定向到 leader。
- 消息流经 consensus 模块——完成定序与复制。
- 服务处理已提交的消息——确定性执行。
- 响应经由 egress 回流——从 leader 到客户端。
这种间接性正是其特性所在。由于每条消息在执行前都已完成定序与复制,服务看到的是一份单一的、达成共识的消息流——在每个节点上都完全一致。
谁参与了这场对话
Section titled “谁参与了这场对话”以下是完整时序中的各个参与者。请记住它们;延迟预算分摊在它们所有人身上。
| 参与者 | 角色 |
|---|---|
| Aeron Cluster Client | 你的应用的客户端库 |
| Aeron Cluster Leader Node | 接受写入的节点 |
| Aeron Cluster Member Node (Follower) | 复制日志 |
| Consensus Module | Raft 实现;对条目进行定序与复制 |
| Aeron Archive | 将日志条目持久化到磁盘 |
| Service Container | 承载你的集群化服务 |
| Customer Built Cluster Logic | 你的业务代码(撮合引擎等) |
完整调用时序(24 步)
Section titled “完整调用时序(24 步)”整段旅程分为四个阶段。自上而下读一遍,延迟的故事便会自行浮现。
阶段 1 —— 客户端连接(第 1-6 步)
Section titled “阶段 1 —— 客户端连接(第 1-6 步)”客户端可以连接到任意节点。如果该节点是 follower,请求会被重定向到 leader。随后,连接本身也会被记录到日志中。
要点在于:连接这件事本身也要经过日志。会话从第一次握手起就是持久化的。
阶段 2 —— 请求处理(第 7-14 步)
Section titled “阶段 2 —— 请求处理(第 7-14 步)”这是 consensus 这一跳。leader 在本地追加请求,并并行地把它复制给各个 follower。只有当一个 quorum 确认后,才会提交。
这一阶段主导了整个延迟预算。leader 自己也计入 quorum(quorumThreshold = n/2 + 1,ClusterMember.java),所以 3 节点集群只需 一个 follower 完成追加到 archive并回送 ACK 即可提交。这一来回——复制、持久化、确认——正是 p99 的栖身之处。
阶段 3 —— 服务执行(第 15-17 步)
Section titled “阶段 3 —— 服务执行(第 15-17 步)”只有已提交的日志片段才会到达服务。执行是确定性的——相同的输入、相同的状态变更,在每个节点上都一样。
你的撮合引擎在这里运行。因为它永远只看到已提交、已定序的消息,它从不需要考虑共识、重试或复制。请让 onSessionMessage() 保持精简:这里位于热路径上,任何内存分配或阻塞调用都会直接反映在 p50 上。
阶段 4 —— 响应回到客户端(第 18-24 步)
Section titled “阶段 4 —— 响应回到客户端(第 18-24 步)”响应并不是抄近路回到客户端。它同样要经过共识——记录日志、复制、提交,然后再投递。
因此,单个请求会穿越共识两次——进来时一次,出去时一次。这就是 exactly-once 语义和干净重放所付出的代价。
这对调优意味着什么
Section titled “这对调优意味着什么”把各阶段对应到你的延迟目标,优先级便一目了然:
- p99 主要落在阶段 2 和阶段 4——也就是两次共识往返。更快的 follower 磁盘和抖动更低的节点间链路,对 p99 的改善超过你单独在 leader 上做的任何事情。
- p50 主要落在阶段 3——也就是你的
onSessionMessage()逻辑。确定性加上精简的热路径,能把中位数压低。 - 吞吐量由 consensus 模块的批处理能力决定——每次往返中它能追加并复制的请求越多,上限就越高。ingress 和 egress 都受其制约。
由于每个请求都要缴两次共识税,最划算的优化几乎总是让 quorum 往返更快——而不是优化中间只运行一次的服务代码。