一、WAL 是什么
WAL(Write-Ahead Logging,预写日志)是 PostgreSQL 的持久化核心机制。
核心原则:任何数据修改,必须先把变更写入日志文件,再修改实际数据页。
二、WAL 解决了什么问题
没有 WAL 的世界
UPDATE user SET name='Alice' WHERE id=1
步骤:
1. 把数据页从磁盘加载到内存 (Shared Buffer)
2. 修改内存中的数据页
3. 将数据页写回磁盘
问题:如果第 3 步执行到一半机器断电 → 数据页写了一半 → 数据永久损坏
有了 WAL
UPDATE user SET name='Alice' WHERE id=1
步骤:
1. 把数据页加载到内存
2. 修改内存中的数据页
3. ✅ 先把变更写入 WAL 文件(顺序写,极快)
4. 再把数据页写回磁盘(checkpoint 时才做)
崩溃恢复:重启后 replay WAL 日志 → 数据恢复到一致状态
三、WAL 的存储结构
$PGDATA/pg_wal/
000000010000000000000001 ← 每个文件默认 16MB
000000010000000000000002
000000010000000000000003
...
WAL Record 内容
┌─────────────────────────────────────────────────────┐
│ LSN (日志序列号) │ 操作类型 │ 表OID │ 变更数据 │
│ 0/1234ABCD │ UPDATE │ 16384 │ old + new │
└─────────────────────────────────────────────────────┘
- LSN(Log Sequence Number):单调递增,唯一标识每条日志位置
- 操作类型:INSERT / UPDATE / DELETE / COMMIT 等
- 变更数据 :
before(旧值)+after(新值)
四、WAL 的三大用途
WAL 文件
│
├── 1. 崩溃恢复
│ 重启后 replay 未持久化的变更
│ 保证 ACID 中的 D(Durability 持久性)
│
├── 2. 流复制(Streaming Replication)
│ 主库 WAL → 实时推送给从库
│ 从库 replay → 保持数据同步
│ 实现高可用 / 读写分离
│
└── 3. Logical Decoding(逻辑解码)
解析 WAL 中的变更为结构化事件
供 CDC 工具(Debezium 等)消费
实现实时数据同步
五、WAL 的两种级别
| 级别 | 配置 | 说明 |
|---|---|---|
replica(默认) |
wal_level = replica |
支持流复制,不支持逻辑解码 |
logical |
wal_level = logical |
在 replica 基础上,额外记录逻辑变更信息,供 CDC 使用 |
开启 CDC 前,DBA 需要确认:
sql
SHOW wal_level;
-- 需要返回 logical
六、CDC 是什么
CDC(Change Data Capture,变更数据捕获) 是一种捕获数据库中数据变更并将变更实时传递给下游系统的技术。
核心思想
不扫全表,只捕获「发生了什么变化」
传统全量同步:SELECT * FROM table → 每次全量扫描
CDC 增量同步:监听日志 → 只传递 INSERT/UPDATE/DELETE 事件
CDC 捕获的事件格式
json
{
"op": "u",
"before": {
"id": 1,
"name": "Bob"
},
"after": {
"id": 1,
"name": "Alice"
},
"source": {
"table": "user",
"ts_ms": 1718600000000
}
}
七、CDC 的作用
| 场景 | 说明 |
|---|---|
| 数据库同步 | DB → Elasticsearch / Redis / 其他数据库 实时同步 |
| 微服务解耦 | 一个服务的数据变更,自动通知其他服务 |
| 审计日志 | 记录谁、什么时候、改了什么 |
| 缓存失效 | DB 数据变更 → 自动淘汰对应缓存 |
| 数仓 ETL | 增量同步到数据仓库,替代定时全量抽取 |
八、基于 WAL 的 CDC 架构
PostgreSQL
└── WAL (wal_level=logical)
│
│ Logical Replication Slot
│ (PG 保留 WAL 直到 slot 消费完)
▼
Debezium Connector
(读取并解析 WAL logical decoding 输出)
│
▼
Kafka Topic
(salesdata.public.salesdata_master_info)
│
├──▶ Kafka Connect ES Sink → Elasticsearch
├──▶ Consumer App → 业务处理
└──▶ Kafka Connect JDBC → 其他数据库
与当前项目的对比
| 当前方案(全量扫表) | CDC 方案 | |
|---|---|---|
| 触发方式 | 定时任务 | 数据变更实时触发 |
| 同步范围 | 全量(百万级) | 仅变更的行(极少) |
| 内存压力 | 高(OOM 风险) | 极低 |
| 延迟 | 分钟级 | 毫秒级 |
| 代码侵入 | 大 | 零侵入 |
| 漏数据风险 | 有(时间窗口问题) | 无(日志不丢) |
九、Replication Slot 注意事项
sql
-- 查看当前 slot
SELECT slot_name, plugin, active, restart_lsn FROM pg_replication_slots;
-- ⚠️ 风险:如果 Debezium 停止消费,PG 会保留 WAL 不删除
-- WAL 文件积累 → 磁盘撑爆
-- 建议:监控 pg_replication_slots 中的 lag
十、小结
WAL 是 PostgreSQL 的基础设施
├── 保证数据不丢(崩溃恢复)
├── 实现高可用(流复制)
└── 支撑 CDC(Logical Decoding)
└── Debezium 利用 CDC
└── 实现 PG → Kafka → ES 实时同步
解决全量扫表 OOM 问题