当集群成员关系发生变化——某个节点离开、加入,或网络分区将集群切分为两半——pgrac 需要在毫秒到秒级内重建全局共享状态,才能继续提供服务。这个过程称为 Reconfiguration,是 RAC 架构可用性设计中最复杂、代价最高的环节。
Reconfiguration 分三个阶段串行推进:Freeze(冻结) 让所有节点的 GES / GCS 入口停止接受新请求;Rebuild(重建) 在存活节点间重新分配资源 master、重建 GRD、合并故障节点遗留的 PI 链;Thaw(解冻) 激活新拓扑,backend 恢复正常执行。三个阶段的典型总耗时小于 3 秒(增量重建路径),已提交事务在整个过程中零丢失。本章建立理解这一机制所需的概念框架:触发条件、三阶段协议、CSSD 检测路径、Merged Redo Apply 原理、失败保证,以及运维监控实践。
Reconfiguration 由 CSSD(Cluster Synchronization Service Daemon) 在检测到集群成员关系变化后触发。触发场景分四类:
任何触发场景都走同一条 3 阶段状态机(§5.2)。区别只在于重建范围:节点退出 / 故障 / hang 需要接管其 master 的全部资源;节点加入需要将部分资源 master 迁入新节点以均衡负载。初版实现两种情况均走全量重建路径,增量重建作为二期优化目标。
| 场景 | 触发来源 | 典型耗时 | 备注 |
|---|---|---|---|
| 节点计划退出(shutdown / 维护) | 节点主动通告 CSSD | < 3 秒 | 最 graceful,fence 非必要 |
| 节点故障 / crash(进程崩溃) | CSSD 心跳超时 + quorum 决议 | < 5 秒 | 需 fence 确认写停止后才进 Rebuild |
| 网络分区 | 网络心跳 misscount 超时 | 5–15 秒 | 多数派继续服务;少数派被 fence |
| 节点 hang(OS / IO hang) | disktimeout 超时 | 10–30 秒 | disktimeout 宽于 misscount,需等磁盘心跳也超时 |
网络分区场景下,两侧都认为对方是少数派——这正是 split-brain 问题的根源。pgrac 通过 §5.5 所述的 voting disk 仲裁机制解决:只有赢得 quorum 的一侧允许继续执行 Reconfiguration;落败一侧在被 fence 之前无权修改共享状态。
Reconfiguration 状态机在 cluster/membership/reconfiguration.c 中实现,以四状态 DAG 推进:stable → freezing → rebuilding → thawing → stable。
Freeze(冻结) 是进入 Reconfiguration 的第一步,也是代价最高的步骤。所有实例的 GES / GCS 入口暂停接受新的全局锁请求和 Cache Fusion block transfer;每个 backend 在进入临界路径(ReadBuffer、LockAcquire、GetSnapshotData、XLogInsert)时通过统一宏 CHECK_FROZEN() 检查冻结标志,若已冻结则阻塞等待 thaw。新事务在此期间挂起;已持有资源的事务不被中断,只是无法推进。Freeze 阶段目标耗时 ≤ 2 秒。
Rebuild(重建) 是实质性的状态重建。存活节点通过 Interconnect 协商,重新选定每个资源的 master 节点(资源在节点间重新分布);GRD 元数据重建完成后,故障节点遗留的 PI 链被合并进来,执行 Merged Redo Apply(§5.4);故障节点上未提交的事务被回滚或由存活节点代为补完。全量重建目标耗时 ≤ 10 秒,增量重建(二期)≤ 3 秒。
Thaw(解冻) 激活新拓扑:所有 backend 的本地资源 master 缓存强制刷新;冻结屏障解除,CHECK_FROZEN() 路径放行;GES / GCS 入口重新接受请求;被阻塞的事务和新事务继续执行。Thaw 目标耗时 ≤ 2 秒。
T0 ──── T1 ──────── T2 ──── T3
│ │ │ │
Detect Freeze Rebuild Thaw
│ │ │ │
↓ ↓ ↓ ↓
heartbeat GES/GCS master 重选 + 新拓扑
丢失 入口暂停 GRD 重建 生效
fence backend PI 链合并 backend
触发 阻塞 恢复
|<-- 典型 < 3 秒 -->|
阶段时间预算(初版全量重建路径):
| 阶段 | 目标耗时 | 超时行为 |
|---|---|---|
| freezing | ≤ 2 秒 | 超时后 CSSD 强制升级为集群重启 |
| rebuilding | ≤ 10 秒(全量)/ ≤ 3 秒(增量,二期) | 超时后升级为集群重启 |
| thawing | ≤ 2 秒 | 超时后降级为节点重启 |
Brownout 是 Reconfiguration 期间业务可见的中断窗口,等于 T1 到 T3 的时长(Freeze 入口暂停到 Thaw 完成)。三阶段总 brownout 目标 ≤ 15 秒(全量),增量优化后 ≤ 3 秒。pg_stat_cluster_reconfig 视图记录每次 Reconfiguration 各阶段的实际耗时,供运维监控和 SLA 核对。
CSSD 的检测是整条 Reconfiguration 链路的起点。CSSD 同时维护三路心跳,任一路超过对应阈值且 quorum 决议通过,才触发 Reconfiguration 信号:
/dev/watchdog 或 IPMI/BMC 集成,确认 OS 层面没有僵死(防止进程还在响应网络心跳、但 DB 子系统已死的情形)。三路心跳任一超时后,CSSD 触发 quorum 仲裁(#2);仲裁决出少数派后,多数派发起 fencing(#3),fence 完成确认后才进入 Reconfiguration 的 Freeze 阶段。这一串行依赖关系保证了 Rebuild 阶段开始时故障节点已经被强制隔离,不再有写共享存储的能力。
CSSD 通过两个独立阈值防止单路心跳误判导致频繁 brownout:
misscount(默认 30 秒):网络心跳连续丢失超过此阈值,CSSD 认为网络路径不可达。适用于快速检测进程 crash 或网络断连,但对瞬时抖动(GC pause、网络闪断)设有一定容忍窗口。
disktimeout(默认 200 秒):磁盘心跳(voting disk slot)更新时间戳超过此阈值未见更新,CSSD 认为节点出现 IO hang 或已死机。disktimeout 显著宽于 misscount,因为磁盘 IO 本身受存储延迟、OS 调度影响,短暂延迟不代表节点失联。
双阈值的组合逻辑:网络心跳先行,misscount 触发后进入 quorum 仲裁;若 quorum 无法判定(例如三节点中两节点断网但磁盘心跳仍存活),则继续等待 disktimeout 到期。disktimeout 到期是"最终裁定"——此时无论网络状态如何,都认定节点失联并执行 fence。两个阈值均可通过 GUC 调整,Oracle 等值为默认值起点。
Freeze 阶段开始的前提是 fence 完成(或 disktimeout 超时确认无法 fence 时升级处理)。这个前提约束了 Reconfiguration 的最短触发延迟:即使进程 crash 立刻被 CSSD 检测到,也需要等待 fence 信号(通过 SCSI-3 PR 或 STONITH)确认后才能解冻,避免 Rebuild 期间故障节点"幽灵写入"共享存储。
Rebuild 阶段最复杂的子任务是合并故障节点的 WAL redo。在 pgrac 集群中,每个节点维护独立的 WAL stream;故障时,故障节点上已持久化但尚未广播给所有节点的 WAL record 需要被存活节点读取并按正确的 SCN 顺序合并回放,才能确保 GRD 中的 block 状态、PI 链、ITL slot 与 WAL 一致。
为什么不是简单串行顺序:每个节点的 WAL stream 只在本节点内单调递增;不同节点的 SCN 是交叉分布的,不存在"先 replay 节点 1 再 replay 节点 2"这样的天然顺序。若按节点顺序串行回放,会破坏跨节点事务的因果关系——例如节点 2 的某次写依赖于节点 1 的前一次写,必须保证 replay 时后者先于前者。
Merged Redo Apply 的正确做法:对所有存活节点(以及从共享存储中读取的故障节点 WAL)的 stream 进行 k-way merge,按 commit_scn(低 56 位 local_scn 部分)排序,得到全局因果有序的 replay 序列。同 SCN 的 tie-break 使用 LSN + node_id 二级排序(对应 scn_recovery_cmp() API,详见 Chapter 4 §4.3)。合并后的序列按顺序逐条 replay,保证 GRD 重建结果与单节点串行执行语义等价。
Node 1 stream: ─●─●─●─●──────●─ (SCN: 42, 43, 50, 51, 61)
Node 2 stream: ─●─●─●────●─●─── (SCN: 12, 44, 45, 55, 60)
Node 3 stream: ─●─●───────────── (SCN: 8, 47)
↓ 按 SCN 排序合并 ↓
Merged: ●─●─●─●─●─●─●─●─●─● (SCN: 8, 12, 42, 43, 44, 45, 47, 50, 51, 55, 60, 61)
replay 顺序
PI 链合并是 Merged Redo Apply 的配套操作:每个 block 在多节点间可能存在多版本 Past Image;Rebuild 阶段在重放 redo 的同时,将故障节点持有的 PI 合并进存活节点的 PI 链,维持 GRD 中 PI 链的完整性,确保后续的 Cache Fusion block transfer 能正确服务旧版本读请求。
Merged Redo Apply 的总工作量取决于故障节点 WAL 的积压量(即从上次 checkpoint 到故障时刻产生的 WAL 量)和 PI 链的长度。在增量重建路径中,只需 replay 故障节点 master 资源对应的 WAL,大幅缩短了 Rebuild 阶段耗时。
已提交事务零丢失是 pgrac Reconfiguration 最核心的承诺。任何 Freeze 前已提交的事务,其 WAL record 已持久化到共享存储(redo log),在 Rebuild 的 Merged Redo Apply 阶段必然被 replay。Freeze 期间新提交的事务被阻塞而非丢弃——backend 在 CHECK_FROZEN() 处等待,commit 路径在 Thaw 后继续执行。
split-brain 防护通过两层机制叠加实现:
第一层是 voting disk 仲裁(#2):集群分区后,只有持有多数票(通常 ≥ N/2+1 个节点)的一侧才能赢得 quorum;落败一侧的节点无权发起 Reconfiguration,自动停写。
第二层是 fencing(#3):SCSI-3 Persistent Reservation 在存储 HBA 层拒绝少数派的 I/O 请求(RESERVATION_CONFLICT),即使少数派进程仍在运行也无法写入共享存储;STONITH 作为兜底,在 SCSI-3 PR 不可用时通过 IPMI/BMC 强制重启少数派物理机。
两层保护相互冗余:任一生效即可防止 split-brain 写入。只有在 fence 完成(或 disktimeout 超时确认节点已死)之后,Rebuild 阶段才被允许开始修改 GRD。
未提交事务的处理:Reconfiguration 完成后,故障节点上所有未提交事务(xmin 未提交、CLOG 未标记 committed)均被视为已中止;存活节点在 Rebuild 期间完成这些事务的回滚,在 Thaw 后新快照中它们对所有节点不可见。
初版实现中,跨 Reconfiguration 的长事务会被中断而非继续。Freeze 阶段 backend 阻塞,但若 Rebuild 耗时超过某阈值(默认 30 秒),未完成事务会被强制终止并向客户端返回错误。这是正确性换实现复杂度的工程选择;Oracle 11g+ 支持长事务在 Reconfiguration 后继续,这一能力作为 pgrac 二期优化目标。
kill -9 演练:在计划维护窗口内,向单节点发送 kill -9 $postmaster_pid 是最直接的 Reconfiguration 演练方式。CSSD 的 misscount 阈值(默认 30 秒)内若没有配置降低,演练会等待约 30 秒后触发;如需快速演练,可在测试集群将 cssd.misscount 降至 5 秒。演练后观察 pg_stat_cluster_reconfig 视图的 reconfig_count、last_reconfig_duration_ms 和各阶段耗时字段,确认 brownout 在目标 SLA 内。
Reconfiguration 频次监控:非计划 Reconfiguration 频次异常(例如 1 小时内超过 3 次)是网络抖动、存储 I/O 抖动或 backend hang 的早期信号。建议配置告警规则:
-- 查询最近 1 小时的 reconfig 次数
SELECT reconfig_count, last_reconfig_at, last_reconfig_duration_ms
FROM pg_stat_cluster_reconfig;
reconfig_freeze_duration_ms 和 reconfig_rebuild_duration_ms 分别追踪两个最耗时阶段;若 rebuild 耗时持续走高,通常意味着 PI 链积压过长或 Interconnect 带宽不足,需要优化 checkpoint 频率或扩容网络带宽。
应用层 retry:客户端在 brownout 期间收到连接中断或超时错误(而非 SQL 错误),应实施 exponential backoff retry:首次 retry 间隔 100 ms,最多 retry 5 次,最大间隔 5 秒。pgrac 的 Thaw 完成后,新连接可立即提供服务;持久连接池(如 PgBouncer)配置 server_connect_timeout = 10s 可覆盖大多数 brownout 窗口。应用层不应将 Reconfiguration 引起的连接中断与业务错误混淆——Reconfiguration 是正常的集群自愈行为,客户端重试后数据状态一致。
深度协议细节请参阅以下资源:
CHECK_FROZEN() 宏注入点、状态机转换条件、阶段间握手消息格式、pg_stat_cluster_reconfig 字段定义、增量重建算法设计Chapter 6 — Wait Events Reference 将介绍与 Reconfiguration 相关的等待事件细节,包括 reconfig_freeze(backend 在冻结屏障阻塞)、reconfig_rebuild(GRD 重建等待)、reconfig_thaw(新拓扑生效等待)等事件的触发条件、典型持续时间和诊断方法。