openGauss 没有用 PG 原生的 SyncRepWakeQueue 批量唤醒PG 原生的等待模型PostgreSQL 使用的是共享内存双向链表队列WalSndCtlData.SyncRepQueue[NUM_SYNC_REP_WAIT_MODE]后端进入等待1. 申请SyncRepLock2. 把自己插入SyncRepQueue[mode]按 LSN 排序3.syncRepState SYNC_REP_WAITING4. 释放SyncRepLock5. 等自己的latchwalsender 更新 LSN 后1. 申请SyncRepLock2. 调用SyncRepWakeQueue()—— 遍历队列把 LSN 满足的所有 backend 一次性全部唤醒3. 释放SyncRepLock这样 N个backend排队一次唤醒全部没有惊群。openGauss 的等待模型openGauss 没有用这个队列机制而是引入了一个串行锁walSyncRepWaitLock// syncrep.cpp:496-511 if (LWLockAcquireOrWait(walSyncRepWaitLock, LW_EXCLUSIVE)) { WalSndCtl-syncWaitProc t_thrd.proc; // 记录当前等锁的人 ResetLatch(t_thrd.proc-procLatch); WaitLatch(t_thrd.proc-procLatch, ..., 1000L); // 最多等 1 秒 WalSndCtl-syncWaitProc NULL; LWLockRelease(walSyncRepWaitLock); }同一时刻只有 1 个 backend 持有这个锁、处于“可被唤醒”状态其他 N-1 个 backend 阻塞在锁上。唤醒链路是walsender 更新LSN → SyncRepWakeBackend() → SetLatch(syncWaitProc-latch)→ 那1个backend醒来检查LSN释放锁→ 下一个backend获得锁成为新的syncWaitProc→ 等待下次LSN更新再被唤醒或等1秒超时性能问题确实存在惊群问题是的有。每个 walsender 刷新 LSN 后只唤醒 1 个 backend如果 N 个 backend 都在等需要 N 次 LSN更新或1秒超时才能轮完。对比 PG 原生方案┌──────────┬──────────────────────────────┬────────────────────────────────┐│ 维度 │ PG 原生 (SyncRepQueue) │ openGauss (walSyncRepWaitLock) │├──────────┼──────────────────────────────┼────────────────────────────────┤│ 等待方式 │ 共享内存链表队列 │ 串行锁排队 │├──────────┼──────────────────────────────┼────────────────────────────────┤│ 唤醒方式 │ 一次唤醒所有满足LSN的backend │ 只唤醒当前持锁的1个backend │├──────────┼──────────────────────────────┼────────────────────────────────┤│ 并发等待 │ N个backend同时等latch │ 只有1个在等其余阻塞锁 │├──────────┼──────────────────────────────┼────────────────────────────────┤│ 惊群 │ 无 │ 有逐个唤醒 │├──────────┼──────────────────────────────┼────────────────────────────────┤│ 适用场景 │ 通用 │ 特定优化场景 │└──────────┴──────────────────────────────┴────────────────────────────────┘为什么 openGauss 这么改这段代码注释说得很清楚syncrep.cpp:336▎ Each proc try to lock walSyncRepWaitLock, and only one backend can get that lock, other backends will wait for it. The backend▎ which get lock will wait latch for a while. If it is waked by WalSnder or wait time out, it will release lock. And all backends▎ will reloop again.这是 openGauss 针对分布式场景ENABLE_MULTIPLE_NODES 等做的特殊改造。核心原因是1. PG 的 SyncRepQueue 机制是为单机设计的在分布式架构下多个 DN 之间需要同步协调批量队列唤醒的语义不够清晰2. 串行锁简化了状态机——只有持有锁的那个人需要关心 LSN 是否满足其他人只是排队等锁避免了多 backend 同时被唤醒后的竞争3. 1秒超时兜底——即使某个 backend 拿锁后没被唤醒最多等1秒就会醒来重新参与下一轮竞争但你说得对确实有性能隐患在高并发同步复制场景下比如大量 backend 同时 COMMIT 且都要求 sync replication- 每个 backend 需要等前面一个被唤醒 检查 释放锁才能轮到下一个- 串行化程度高延迟会随等待 backend 数量线性增长- PG 原生方案是 O(1) 唤醒所有而 openGauss 是 O(N)这是一个正确性优先于性能的设计取舍在分布式场景下可能是合理的但单机高并发场景下确实不如 PG 原生方案高效。