pgrac 的集群通信层抽象为 cluster.interconnect_tier GUC 控制的 Interconnect Tier。所有上层子系统(Cache Fusion、GES、SCN 广播、CSSD 心跳、reconfig coordinator)都通过同一组 cluster_ic_* API 调用通信层;底层 vtable 把调用路由到当前 Tier 的实装。Tier 选择在 postmaster 启动时决定,运行时不可变。
当前 Stage 2 范围:tier1 = TCP(spec-2.2 loopback 单机伪集群、跨主机 TCP)。Stage 6+ 计划:tier1 / tier2 / tier3 = 逐步升级的 RDMA 实现(spec-6.1 起,目标 3–10 μs p99)。本章按当前 Stage 2 设计描述协议层(spec-2.3 Envelope ABI + spec-2.4 framing),并附 Stage 6 RDMA 路线图作为预告。
"Tier1 = InfiniBand / Tier2 = RoCE / Tier3 = TCP" 这种 Oracle 风格的硬件命名不对应 pgrac 的 cluster.interconnect_tier 枚举。pgrac 的 tier 编号代表"实现成熟度",所有 RDMA 替换都发生在 Stage 6 之后(详见 §7.5)。等待事件中 L1–L4 标签(wait-events-design.md §10)是另一套延迟桶分类,与本枚举无关。
cluster.interconnect_tier GUC 是 PGC_POSTMASTER 类型的枚举,定义在 cluster-ic-design.md。当前合法值取决于 stage:
| Stage | 合法枚举值 | 未实现枚举值的行为 |
|---|---|---|
| Stage 0.18(早期) | stub | ereport(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED),postmaster 启动失败 |
| Stage 2(当前) | stub、tier1 | 同上:tier2/tier3 在 Stage 2 被拒绝 |
| Stage 6+(规划) | stub、tier1、tier2、tier3 | tier3 = RDMA mlx5dv direct verbs 目标态 |
低层 vtable 接口(ClusterICOps)固定 5 个函数指针,从 Stage 0.18 起冻结:
struct ClusterICOps {
int (*send_bytes)(int32 target, const void *buf, size_t len);
int (*recv_bytes)(int32 *out_sender, void *buf, size_t bufsize, size_t *out_received);
int (*tier_init)(void);
int (*tier_shutdown)(void);
const char *tier_name;
};
每个 tier 提供一份 vtable 实装:Stage 2 是 ClusterICOps_TCP;Stage 6.1 起逐步加入 ClusterICOps_RDMA_Tier1/Tier2/Tier3。上层永远调用同一组高层 API(§7.3),不感知 vtable 切换。
Stage 2 分两步把 tier1 从 stub 替换为 TCP 实装:
B_IC_LISTENER 后台进程接受跨主机连接。TCP 路径走标准 socket(SO_KEEPALIVE + TCP_KEEPIDLE/INTVL/CNT,配合 spec-2.5 CSSD 心跳形成两层 dead 检测,详见 Ch 5 §5.3)。Stage 2 没有 RDMA 路径——所有 RDMA 相关 GUC 与代码尚未存在。
典型 Stage 2 TCP 单消息延迟(跨主机以太网)≈ 50 μs;这个数字在 Stage 6+ 切换到 RDMA tier3 后会降到 3–10 μs p99(spec-6.1)。Stage 2 的目标是正确性与协议成熟度,不是延迟优化——Cache Fusion 性能基准在 Stage 6+ 路线落地后才有意义。
spec-2.3 替换了 Stage 0.18 时期 24 字节的 ClusterMsgHeader,引入 36 字节的 ClusterICEnvelope 作为所有 IC 消息的统一信封。Stage 2 起所有 cluster 消息都走 envelope;Stage 6 RDMA 替换底层 transport 时 envelope 格式不变。
Envelope 字段布局(36 字节,固定):
| 偏移 | 大小 | 字段 | 说明 |
|---|---|---|---|
| 0 | 2 B | magic | 0x4943("IC" LE,sanity marker) |
| 2 | 1 B | version | V1 = 1 |
| 3 | 1 B | msg_type | ClusterICMsgType 枚举(见下表) |
| 4 | 4 B | source_node_id | 发送节点 |
| 8 | 4 B | dest_node_id | 目标节点,0xFFFFFFFF = broadcast |
| 12 | 8 B | epoch | cluster_epoch piggyback,spec-2.4 强制校验 |
| 20 | 8 B | scn | Lamport SCN piggyback |
| 28 | 4 B | payload_length | ≤ 16 MB 硬上限 |
| 32 | 4 B | payload_crc32c | CRC32C 覆盖 envelope(除自己)+ payload |
4 条 StaticAssertDecl 锁定 sizeof == 36,以及 epoch@12、scn@20、payload_length@28 三个字段偏移。
消息类型枚举(ClusterICMsgType):
| 值 | 名称 | 来源 spec | 说明 |
|---|---|---|---|
| 0 | 预留 sentinel | — | 非法值,校验直接拒绝 |
| 1 | HEARTBEAT | spec-2.5 | CSSD 心跳 |
| 2 | SCN_BROADCAST | spec-2.9 | 跨节点 SCN 广播 |
| 3 | BOC_BROADCAST | spec-2.10 | BOC 批量推进通知 |
| 4 | GES_REQUEST | spec-2.16 | GES enqueue / convert / release 请求 |
| 5 | GES_REPLY | spec-2.16 | GES grant / convert ack / release ack |
| 6 | CF_BLOCK_SHIP | spec-3.x | Cache Fusion block 传输(Stage 3+) |
| 7 | SINVAL | spec-2.x | 集群级 sinval 广播 |
| 8 | FENCE_NOTIFY | spec-2.28 | fence-lite 通告 |
| 9 | RECONFIG | spec-2.29 | reconfig coordinator 广播 |
| 11 | CSSD_HEARTBEAT | spec-2.5 | CSSD 应用层心跳 payload(12 字节) |
| 255 | CHUNK | spec-2.4 | 大于 16 MB 的 payload 分块包装 |
对外暴露的高层 API(cluster/cluster_ic_router.h):
cluster_ic_register_msg_type(const ClusterICMsgTypeInfo *info) — postmaster 阶段注册 msg_type、handler、producer mask;重复注册 FATALcluster_ic_send_envelope(uint8 msg_type, int32 dest_node_id, const void *payload, uint32 payload_len) — 构造 envelope + CRC + 入站队列cluster_ic_dispatch_envelope(const ClusterICEnvelope *env, const void *payload) — verify + dispatch_table 查表 + 调用 handler(LMON 收信路径)cluster_ic_envelope_build / verify — 构造/校验对(5 参数签名,spec-2.4 起 stateful 拆分)cluster_ic_send_envelope_chunked(uint8 inner_msg_type, int32 dest_node_id, const void *payload, size_t len) — 大 payload chunked 变种Stage 2.3 移除了 Stage 0.18 时期的 ClusterMsgHeader、cluster_msg_send、cluster_msg_recv。cluster_rpc_call(RPC 风格请求/应答)推迟到 Stage 6 后讨论。
spec-2.4 把 envelope 从"格式定义"升级为"校验已激活":epoch 不匹配立即丢帧并计数,Lamport 时钟通过 envelope 字段 piggyback 收敛。
消息走 length-prefix,无分隔字节。接收端永远先读 36 字节 envelope,然后读 envelope.payload_length 字节 payload。magic = 0x4943 是 sanity marker,不是帧分隔符。TCP 走 in-order 交付假设;partial-IO 由 spec-2.2 v1.0.1 的 per-peer 缓冲状态机处理。
Chunking(spec-2.4 §3):超过 16 MB 的 payload 由 cluster_ic_send_envelope_chunked() 包装 16 字节 ClusterICChunkHeader(chunk_seq u32 / chunk_total u32 / total_payload_len u32 / inner_msg_type u8 + 3B pad),外层 envelope msg_type = 255(PGRAC_IC_CHUNK_MSG_TYPE)。默认上限 64 MB,硬上限 256 MB。
每条 envelope 的 epoch 字段(偏移 12,8 字节)由发送端写入 cluster_epoch_get_current()。spec-2.4 接收端 verify 步骤 7:若 env->epoch != current_epoch,立即丢帧(不进 dispatch),LOG 一行,累加 stale_epoch_drop_count,SQLSTATE 53R20 CLUSTER_IC_STALE_EPOCH_DROP。这条机制保证跨 reconfig 的旧 envelope 不会污染新拓扑——reconfig coordinator(Ch 5 §5.2.1)推进 epoch 之后,旧 epoch 的在途消息自动失效。
Stage 2.4 阶段 CLUSTER_EPOCH_INITIAL = 0,epoch 永远保持 0。真正的 epoch++ 在 spec-2.29 reconfig coordinator 中发生(详见 Ch 5)。
每条 envelope 的 scn 字段(偏移 20,8 字节)由发送端填入 cluster_scn_current()。接收端经过 CRC + 认证校验后调用 cluster_scn_observe(env->scn),按 Lamport >= 规则推进本地 SCN。计数器 lamport_observe_advance_count 跟踪触发次数。
这是 SCN 协议(Ch 4)跨节点收敛的核心机制:所有跨节点消息都自动携带 SCN,无需独立的 SCN 广播流量。spec-2.9 / 2.10 提供专门的 SCN_BROADCAST / BOC_BROADCAST msg_type 用于显式收敛点。
Stage 6 production hardening 阶段把 tier1 / tier2 / tier3 替换为 逐步升级的 RDMA 实装。语义不变(envelope ABI 不变、消息类型不变、上层 API 不变),只换 vtable:
| Stage | vtable | 实装重点 | 目标延迟 |
|---|---|---|---|
| 6.1 | ClusterICOps_RDMA_Tier1 | libibverbs 基础封装;replaces TCP in tier1 slot, TCP 保留为 fallback | 10–20 μs |
| 6.2 | ClusterICOps_RDMA_Tier2 | MR 预注册(mr_cache)、zero-copy DMA | 5–10 μs |
| 6.3 | ClusterICOps_RDMA_Tier3 | mlx5dv direct verbs、lock-free 路径;目标态 | 3–10 μs p99 |
Stage 6 RDMA 的设计要点(保留供 Stage 6 落地时落实,当前 Stage 2 尚未实现):
{addr, size} 为 key 维护 LRU 哈希表;首次发送注册并缓存 MR handle,后续命中跳过 ibv_reg_mr()(单次约 2–5 μs 节省)本节的 RDMA 细节是 Stage 6 设计目标,当前实现尚未涉及。任何 pg_cluster_rdma_* 视图、cluster_rdma_* GUC、pgrac_ctl verify rdma 工具都不属于 Stage 2 范围。Stage 6 设计交付前,运维不需要也无法配置这些项。
Cluster: Interconnect 类(5 个事件,wait-events-design.md §10)记录 IC 层延迟。Stage 2 范围内可用的事件:
| 事件 | 触发场景 | 典型延迟 |
|---|---|---|
Interconnect TCP fallback | Stage 2 默认 TCP 路径(也是 Stage 6+ AD-007 L4 桶) | ~50 μs |
Interconnect connect retry | peer 连接断开后指数退避重连 | 100 ms–10 s |
Interconnect tier switch | Stage 6+ 才会触发;Stage 2 不可见 | — |
Interconnect RDMA send | Stage 6+ 才会触发 | — |
Interconnect RDMA recv | Stage 6+ 才会触发 | — |
视图 pg_stat_cluster_wait_events(spec-0.x,wait-events-design.md L1106)按 backend 聚合统计;pg_stat_cluster_wait_events_history 提供时间桶切片。AD-007 的 L1–L4 延迟桶分类(wait-events-design.md §10 L867-887)是等待事件维度的独立分类:L1 RDMA WRITE/READ、L2 RDMA SEND/RECV、L3 verbs queue congestion、L4 TCP fallback——这些标签不对应 cluster.interconnect_tier GUC 的枚举值。
深度协议细节请参阅以下资源:
CF_BLOCK_SHIP(msg_type 6),Stage 3+ 起激活cluster-ic-design.md — 完整设计:vtable ClusterICOps、enum 演进、Stage 0.18 → Stage 2 → Stage 6 演进路径spec-2.3-envelope-abi-ratify-transport-agnostic-api.md — Envelope ABI 冻结版(v0.2, 2026-05-07)spec-2.4-framing-epoch-enforce-lamport-piggyback.md — Framing / epoch 强制校验 / Lamport piggyback 冻结版(v0.2, 2026-05-08)Chapter 8 — Background Processes 介绍 LMON、CSSD、qvotec、LMS、LMD 等守护进程如何通过 IC 框架收发消息:LMON 的消息主循环(dispatch_envelope 入口点)、CSSD 心跳的发送路径、LMS daemon 的 work_queue 模型。