-- 040: Debezium CDC support tables — heartbeat + signal + publication -- -- 经验教训 (来自 rwadurian 事故): -- 1. Debezium ≤2.4 存在 DBZ-7316 bug: 当 outbox 表长时间无写入时, -- confirmed_flush_lsn 停止推进, PostgreSQL WAL 无限积压 (曾导致 306GB WAL) -- 2. heartbeat TABLE 方式比 pg_logical_emit_message() 更可靠: -- - pg_logical_emit_message 写入 WAL 但不经过 publication, Debezium 无法感知 -- - heartbeat TABLE 方式: Debezium 定期 INSERT/UPDATE → 产生 WAL 变更 → -- 经过 publication → Debezium 消费 → 推进 confirmed_flush_lsn -- 3. signal 表用于 Debezium 增量快照 (incremental snapshot): -- - 支持 Kafka 信号通道触发数据重放, 零数据库修改 -- - 出问题时可安全地重新投递 outbox 事件 -- 4. publication 必须包含 outbox + heartbeat + signal 三张表 -- Debezium 心跳表: 防止 WAL 积压 CREATE TABLE IF NOT EXISTS debezium_heartbeat ( id INTEGER PRIMARY KEY DEFAULT 1, ts TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT debezium_heartbeat_singleton CHECK (id = 1) ); -- 初始化心跳行 (Debezium 后续通过 ON CONFLICT DO UPDATE 更新) INSERT INTO debezium_heartbeat (id, ts) VALUES (1, NOW()) ON CONFLICT DO NOTHING; -- Debezium 信号表: 用于增量快照等运维操作 CREATE TABLE IF NOT EXISTS debezium_signal ( id VARCHAR(64) PRIMARY KEY, type VARCHAR(32) NOT NULL, data TEXT ); -- 创建 publication: 包含 outbox + heartbeat + signal 三张表 -- Debezium connector 使用 publication.autocreate.mode=disabled, 直接引用此 publication DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_publication WHERE pubname = 'debezium_outbox_publication') THEN CREATE PUBLICATION debezium_outbox_publication FOR TABLE outbox, debezium_heartbeat, debezium_signal; END IF; END $$;