一、结论(先说清楚)


难度 中等

这个问题非常关键,而且是内核方案必须回答清楚的两个核心风险:

1️⃣ 会不会导致 WAL 暴增
2️⃣ 会不会破坏 WAL 兼容性

我分别给你结论 + 原理 + 定量判断 + 风险控制方案。


✅ 1. WAL 不会“失控暴增”,但会可控增加

  • 增量主要来自 DDL SQL 文本 / payload
  • 对 OLTP 场景影响 非常小
  • 对 DDL-heavy 场景需要优化(可控)

✅ 2. 不会破坏 WAL 兼容性(前提:用现有机制)

如果你用的是:

LogLogicalMessage(..., RM_LOGICALMSG_ID)

👉 那么:

✔ WAL 格式完全兼容
✔ crash recovery 不受影响
✔ 旧版本不会崩(只是忽略 message)


二、WAL 是否会暴增(深入分析)


1️⃣ 你到底往 WAL 里多写了什么?

你新增的是:

XLOG_LOGICAL_MESSAGE
  prefix = "pg_ddl"
  payload = LogicalDDLCommand(二进制)

👉 本质:

每个 DDL 多一条 WAL record


2️⃣ 单条 DDL 大小估算

假设:

CREATE TABLE t1 (
  id int,
  name text
);

payload 大致:

项 大小
header ~40B
pubids ~8B
command_tag ~16B
normalized_sql 80200B
object_identity ~32B

👉 合计:

≈ 150B ~ 400B

3️⃣ 对比 WAL 本身大小

一个普通 INSERT:

heap_insert WAL ≈ 50B ~ 200B

一个 UPDATE:

≈ 100B ~ 300B

👉 结论:

一条 DDL ≈ 几条 DML WAL 的量级


4️⃣ 关键点:DDL 频率极低

现实生产:

类型 QPS
INSERT/UPDATE 1000 ~ 100万/s
DDL 0 ~ 1/s(甚至更低)

👉 所以:

WAL 增量 ≈ 忽略不计(绝大多数场景)

5️⃣ 真正可能膨胀的场景

只有两种情况需要警惕:


❗场景1:自动化系统疯狂 DDL

例如:

每秒 CREATE TABLE / DROP TABLE

👉 会产生:

DDL WAL ≈ 300B * N

❗场景2:超长 SQL

CREATE TABLE t (... 500列 ...)

👉 SQL 本身可能:

10KB+

👉 但注意:

这本来就已经存在:

log_statement = ddl

也会记录类似大小


三、如何控制 WAL 增长(优化建议)


✅ 优化1:不要无脑存原 SQL

你现在设计:

query_string
normalized_sql

👉 建议:

字段 是否必须
normalized_sql ✅ 必须
query_string ❌ 可选(debug用)

👉 可以加参数:

ddl_include_query = off

✅ 优化2:压缩 payload(可选)

可以:

pglz_compress(payload)

👉 对长 SQL 效果很好:

10KB → 2KB

✅ 优化3:结构化替代 SQL(高级优化)

未来可以:

{
  "type": "CREATE_TABLE",
  "columns": [...]
}

👉 比 SQL 小很多


四、WAL 兼容性问题(重点)


1️⃣ 你有没有改变 WAL 格式?

👉 没有 ❗(关键)

你使用:

RM_LOGICALMSG_ID
XLOG_LOGICAL_MESSAGE

这是 PostgreSQL 已存在的 WAL record 类型:

PG_RMGR(RM_LOGICALMSG_ID, "LogicalMessage", ...)

👉 意味着:

项 结果
WAL 格式 ✅ 不变
redo ✅ 不受影响
pg_waldump ✅ 可识别
旧版本 ✅ 可跳过

2️⃣ crash recovery 是否受影响?

不会。

因为:

logicalmsg_redo(...) { /* no-op */ }

👉 说明:

这种 WAL record 不参与物理恢复


3️⃣ 旧版本兼容性

假设:

  • 主库:你改过(支持DDL复制)
  • 备库:旧版本

👉 行为:

WAL → 备库
遇到 XLOG_LOGICAL_MESSAGE
→ 忽略

✔ 不会崩
✔ 不会错误恢复
✔ 只是丢失DDL复制能力


4️⃣ replication protocol 兼容性

你新增:

'D' message

👉 必须做:

proto_version >= N

否则:

👉 老 subscriber 收到未知 message 会报错


👉 正确做法:

START_REPLICATION ... (proto_version=5, ddl=on)

五、真正的风险点(你必须注意)


❗1. WAL 膨胀不是最大问题

真正风险是:

logical slot retention

场景:

  • subscriber 挂了
  • slot 卡住
  • WAL 无法 recycle

👉 现在:

WAL = DML + DDL

👉 你的 DDL 会:

  • 延长 WAL 生命周期
  • 但不是主要因素(DML 才是)

❗2. 超大 DDL 导致 WAL segment 膨胀

极端:

CREATE TABLE t (... 10000 columns ...)

👉 payload = 100KB+


👉 会导致:

  • WAL segment 快速切换
  • replication lag

👉 解决:

max_ddl_message_size

❗3. 逻辑复制 replay 风险(比 WAL 更重要)

不是 WAL 问题,而是:

DDL replay 失败 → 停订阅

六、总结一句话

👉 你的方案在 WAL 层面的影响是:

✔ 增加 WAL(但很小)
✔ 不改变 WAL 格式
✔ 不影响 crash recovery
✔ 不影响物理复制
✔ 对 logical slot 有轻微压力(但可控)

七、最终建议(非常关键)

如果你要上线这个功能,我建议你必须加这 4 个保护:


✅ 1. WAL 控制参数

max_ddl_message_size
ddl_include_query = off

✅ 2. payload 压缩(建议)


✅ 3. proto_version gating


✅ 4. publication 限制

一期只允许:

table + index

八、如果你要更深入(下一步)

我可以帮你继续做两个非常关键的点:


👉 1. pgoutput 如何发送 DDL(完整实现)

包括:

  • prefix 匹配
  • 转成 ‘D’ message
  • proto negotiation

👉 2. apply worker 如何执行DDL(最复杂部分)

包括:

  • 事务顺序
  • 幂等处理
  • 错误恢复
  • search_path 问题

文章作者: growdu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 growdu !
  目录
分类导航
随笔3 AI29 计算机基础13 算法1 博客搭建7 ChatGPT2 集群63 计算机通信1 数据库59 数据库深入93 数据库93 Docker11 DPDK26 编辑工具4 Elasticsearch4 FAQ1 Go Web1 hometown2 编程语言16 人生11 网络9 Linux38 OPC1 openGauss4 页面12 PostgreSQL54 程序员自我修养1 协议11 stock1 存储5 成长之路1 工具20 视频作品1 VPP18 Vue13 Web1 代码示例11 BenchmarkSQL1 PostgreSQL 源码修炼之路14
最热文章
1
PostgreSQL 逻辑复制全链路:以一个真实事务为例,从 `INSERT` 到 `apply` 的源码级旅程
数据库🔥 2162
2
PostgreSQL 逻辑复制 Stream 执行逻辑源码级拆解:从 reorderbuffer 触发到订阅端落盘回放
数据库🔥 1765
3
PostgreSQL 行锁机制源码级深度拆解:4 种锁模式 + xmax + MultiXact 的完整链路
数据库🔥 1656
4
PostgreSQL reorderbuffer.c 函数级源码全集:5615 行 / 95 个函数的逐函数解析
数据库深入🔥 1650
5
PostgreSQL 目录快照源码级深度拆解:系统表读取的 MVCC 真相与失效机制
数据库🔥 1604
6
13 逻辑复制深入
数据库深入🔥 1570
7
0 Postgresql存储、索引及系统优化、主备切换
PostgreSQL🔥 1495
8
PostgreSQL 读一行数据源码级深度拆解:MVCC 在每个环节的落点
数据库🔥 1464
9
PostgreSQL WAL 记录类型完全指南:21 个 RMGR × 80+ 种记录的源码级拆解
数据库🔥 1431
10
一文读懂openguass dcf网络模块
集群🔥 1420
11
PostgreSQL 元数据存储机制:从磁盘文件到内存缓存,`pg_class` 撑起的整个系统表体系
数据库🔥 1411
12
openGauss 并行解码设计原理深度拆解:reader + 多 worker + CSN 三层架构的源码级剖析
数据库深入🔥 1344
13
逻辑复制源码分析
数据库深入🔥 1327
14
PostgreSQL 逻辑复制:catalog 改动、可见性判定与 xmin/xmax 推进全景
数据库深入🔥 1317
15
自托管服务全家桶:从原文方案到可复制实操手册
人生🔥 1278
16
PostgreSQL CREATE_REPLICATION_SLOT 端到端源码分析:从 SQL 到 snapbuild 状态机的完整链路(每个函数每个参数)
数据库深入🔥 1277
17
PostgreSQL syscache 模块源码深度拆解:CatCache 数据结构、LRU 哈希表、cache invalidation 全链路
数据库深入🔥 1216
18
PostgreSQL 18 内核数据结构全景:RangeVar 与 20+ 个核心数据结构源码级拆解
数据库🔥 1158
19
PostgreSQL 逻辑复制里 `RUNNING_XACTS` 写入机制与快照 `xmin / xmax / xip` 的演化:源码级深度拆解
数据库🔥 1119
20
PostgreSQL 分区表:从一行 `PARTITION BY` 到路由热路径的全链路拆解
数据库🔥 1094