一、结论(先说清楚)


难度 中等

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

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 !
  目录
分类导航
随笔2 AI27 算法1 计算机基础13 博客搭建7 ChatGPT2 集群63 计算机通信1 数据库34 数据库深入80 DPDK26 Docker11 Elasticsearch4 编辑工具4 FAQ1 Go Web1 hometown2 编程语言16 网络9 OPC1 Linux38 openGauss4 页面12 PostgreSQL54 程序员自我修养1 协议11 成长之路1 stock1 存储5 工具20 VPP18 视频作品1 Vue13 Web1 代码示例11 数据库15 BenchmarkSQL1 PostgreSQL 源码修炼之路14
最热文章
1
13 逻辑复制深入
数据库深入🔥 1570
2
0 Postgresql存储、索引及系统优化、主备切换
PostgreSQL🔥 1495
3
一文读懂openguass dcf网络模块
集群🔥 1420
4
逻辑复制源码分析
数据库深入🔥 1327
5
PostgreSQL 分区表:从一行 `PARTITION BY` 到路由热路径的全链路拆解
数据库🔥 1094
6
applyparallelworker.c 之 LA 端源码深度解析:Leader Apply Worker 的指挥中枢
数据库深入🔥 1082
7
PostgreSQL Background Worker 全解:从 `RegisterBackgroundWorker` 到逻辑复制 4 类 worker 的全生命周期
数据库🔥 1078
8
PostgreSQL的后台进程walsender分析 - 关系型数据库 - 亿速云
PostgreSQL🔥 1033
9
PostgreSQL 逻辑复制的监控:六张视图 + 一组可执行 SQL,把 publisher/subscriber 的速率与健康度彻底看透
数据库🔥 1032
10
PostgreSQL 逻辑复制支持 DDL 之后:DDL 与 DML 的时序难题(重点:分区表)
数据库🔥 999
11
reorderbuffer.c 源码深度解析:PostgreSQL 逻辑复制的"事务重组引擎
数据库深入🔥 953
12
PostgreSQL 内核开发:读取一张表的 9 步标准流程与缓存全景
数据库🔥 938
13
从 `postgres` 二进制到生产级守护 —— PostgreSQL 最外层模块与启动全流程拆解
数据库🔥 936
14
支持逻辑复制同步 DDL 适配 SQL Server 方案
数据库深入🔥 934
15
PostgreSQL 逻辑复制的 ReorderBuffer 与事务机制:从一行 WAL 到一致性变更流的全链路绑定
数据库🔥 913
16
DDL同步架构(美化版)
数据库深入🔥 908
17
PostgreSQL Latch 机制详解:从一行 SetLatch 到 epoll 的内核之旅
数据库🔥 871
18
pgbench 源码全解:一个 C 文件如何撑起 PostgreSQL 官方压测工具
数据库🔥 860
19
PostgreSQL libpq 机制与缓冲区详解
数据库🔥 850
20
PostgreSQL 逻辑复制 spill 文件深度剖析:从 `xid-*.spill` 到 TPC-C 的增长方程
数据库🔥 845