已采纳
回答正文
回复
讨论正文
该问题的正文与回答。
我负责一条实时 ETL 管道:Kafka 3.5(KRaft,3 broker,ISR=3)→ 自研消费服务(Go 1.22 + pgx v5.7,K8s 4 副本)→ PostgreSQL 16.2(单主库,32C128G,NVMe SSD,同机部署)。写入端 4 个 consumer 实例合计约 120 并发事务,每事务批量 INSERT 5000 行(单表,~3 个二级索引),commit 间隔 200~400ms,整体写入约 200k rows/s。
synchronous_commit = on(默认)时,commit P99 约 85ms,其中 fsync 占 60~70ms(pg_stat_database 的 blks_read 和 pg_stat_bgwriter 的 checkpoint_write_requests 均正常,瓶颈在 WAL fsync 排队)。synchronous_commit = off 后,commit P99 降到 70ms(省 18%),整体吞吐能多撑 ~15%。synchronous_commit = local:P99 降到 78ms,只省 8%,且 crash 时仍可能丢已 commit 的(只保证 WAL 落盘不保证 redo log 同步),收益不明显。wal_buffers = 256MB + max_wal_size = 4GB:对 P99 影响 <2ms,瓶颈不在 buffer 不足。commit_delay = 1000(microseconds,group commit):在 synchronous_commit=on 下 P99 降了 ~3ms,杯水车薪。msg_id UNIQUE)放同一个事务,crash 后重放时靠 UNIQUE 冲突去重。但幂等表本身也在同一个 WAL 里,如果 crash 点在幂等表 commit 之后、业务表 commit 之前(同事务不应该,但 split-brain 场景下有可能),就会出假阳性。synchronous_commit=off 时 crash 后的实际数据丢失窗口(WAL 中未 flush 的字节数 / 行数 / 时间)怎么估算?有没有比"等 crash 了再数"更好的事前量化方法(比如 pg_wal 的 wal_write_lsn vs wal_flush_lsn 的 lag 分布)?synchronous_commit=off 的 18% P99 收益 vs 90 秒重放窗口 + 幂等表兜底的复杂度,你们线上怎么选?有没有"分级"方案——比如核心表 on、日志表 off,在同一个 PG 实例上按表/按事务切换?synchronous_commit=off 时,WAL 重放是否保证这个原子性?有没有已知 case 出现"幂等表在、业务表不在"的假阳性?引用相关讨论: