WAL Files(WAL 文件组织)
上一节讲了表的物理文件是「一组按 1GB 切分的文件」。WAL 也一样,但它切分的单位不是 1GB,而是 16MB,并且它的文件名不是随意的 OID,而是一串编码了时间线与 LSN 的十六进制。读懂这串文件名,就能从磁盘上直接推断出「WAL 写到哪了、有多少是老文件、能不能删」。本节讲解 WAL 文件的命名规则、生成与回收机制,以及如何用 pg_waldump 直接翻阅 WAL 内容。
前置知识
阅读本节前,建议先了解:Visibility Map(可见性映射)
基础概念
WAL(Write-Ahead Log,预写式日志)在磁盘上的落点就是 PGDATA 下的 pg_wal 目录。理解这个目录,需要先统一以下术语:
| 术语 | 英文 | 说明 |
|---|---|---|
| WAL | Write-Ahead Log | 预写式日志,所有修改必须先写日志再写数据文件 |
| WAL 段文件 | WAL Segment File | WAL 的物理文件,默认每个 16MB |
| 段大小 | wal_segment_size | 段文件大小,只能在 initdb 时指定,默认 16MB |
| 日志文件号 | Log File Number | 段文件名的中间 8 位,每 256 个段算一个"日志文件" |
| 时间线 | Timeline | 段文件名最前 8 位,每次恢复结束会 +1,用于区分分支 |
| 段号 | Segment Number | 段文件名最后 8 位,在同一日志文件内的序号 |
| 回收 | Recycling | 不再需要的段文件被改名复用,而非删除 |
| 归档 | Archiving | 把写满的段文件复制到外部存储(备份用) |
| 截断 | .partial | 未写满就被中断的段文件,恢复时会被截断到有效长度 |
pg_wal 目录里都有什么
pg_wal 不只有段文件,还包含若干辅助文件与子目录:
$PGDATA/pg_wal/
├── 000000010000000000000001 # WAL 段文件(16MB)
├── 000000010000000000000002 # WAL 段文件(16MB)
├── 00000001000000000000000A.history # 时间线历史文件(发生过恢复才有)
├── 00000001000000000000000A.00000028.backup # 基础备份标签文件
├── 00000001000000000000000B.partial # 未写满的段文件(崩溃/关机时产生)
└── archive_status/ # 归档状态标记目录
├── 000000010000000000000001.done # 已成功归档
└── 000000010000000000000002.ready # 等待归档各文件类型的职责:
| 文件/目录 | 命名特征 | 作用 |
|---|---|---|
| 段文件 | 24 位十六进制 | 真正存放 WAL 记录,16MB 一个 |
.history | <文件名>.history | 记录时间线切换历史,恢复时用来选择分支 |
.backup | <文件名>.<LSN 高位>.backup | 基础备份(pg_basebackup)的元信息标签 |
.partial | 以 .partial 结尾 | 崩溃或快速关机留下的未完整段文件 |
archive_status/ | 内含 .ready / .done | 归档进度标记,.done 后文件才可被回收 |
段文件名的三段结构
24 位十六进制文件名由三段各 8 位组成,这是 WAL 文件组织最核心的规则:
00000001 00000000 00000001
└──┬───┘ └──┬───┘ └──┬───┘
│ │ └── 段号(Segment Number)
│ │ 同一日志文件内的序号,16MB 段下范围 0x00 ~ 0xFF
│ │
│ └─────────── 日志文件号(Log File Number)
│ LSN 的高 32 位,等价于「第几个 4GB 区间」
│
└──────────────────── 时间线(Timeline ID)
初始为 1,每次基于备份恢复并提升后 +1把 LSN 换算成文件名的公式如下(以默认 16MB 段为例):
给定 LSN = 高32位/低32位(如 0/1600000)
日志文件号 = LSN 高 32 位 → 0x00000000
段号 = LSN 低 32 位 ÷ wal_segment_size → 0x1600000 ÷ 0x1000000 = 1
文件名 = 时间线 + 日志文件号 + 段号
= 00000001 00000000 00000001
反推:段文件内的字节偏移 = LSN 低 32 位 mod wal_segment_size
= 0x1600000 mod 0x1000000 = 0x600000 = 6291456为什么是「256 个段一个日志文件」
16MB × 256 = 4GB = 2³² 字节,正好是一个 32 位无符号整数能表示的范围。因此「日志文件号」就等于 LSN 的高 32 位,「段号」就是低 32 位除以段大小。文件名的设计完全是 LSN 位域的直接映射,不需要额外查表。
核心机制
WAL 段的生成与切换
WAL 是顺序追加写的。当写入位置走到当前段文件末尾时,就要切换到下一个段文件:
事务产生 WAL 记录
│
▼
写入当前段文件的写入位置(write pos)
│
├─ 未到段尾(16MB)→ 继续追加 ✔
│
▼ 已到段尾
切换段文件(switch)
│
├─ 有可回收的旧段文件 → 改名复用(recycle),避免创建新文件
├─ 无可用旧文件 → 新建一个 16MB 文件
│
▼
写入位置进入新段文件,日志文件号/段号按上述公式递增切换可以由两种情况触发:
- 自然写满:写入位置到达段尾。
- 主动切换:执行
pg_switch_wal(),或归档场景下archive_timeout到期。
-- 查看当前写入到哪个段文件、偏移多少
SELECT pg_current_wal_lsn() AS current_lsn,
pg_walfile_name(pg_current_wal_lsn()) AS current_file,
pg_walfile_name_offset(pg_current_wal_lsn()) AS file_and_offset; current_lsn | current_file | file_and_offset
--------------------+----------------------------+--------------------------------------
0/1600000 | 000000010000000000000001 | (000000010000000000000001,6291456)current_lsn是当前写入位点,格式为高32位/低32位。current_file就是当前活跃的段文件名,格式规则如上推导。file_and_offset同时给出文件名与段内字节偏移,用于精确定位。
WAL 文件的生命周期
一个段文件从创建到被回收,会经历几个明确状态:
新建 / 复用
│
▼
① 活跃(current) ← 正在被写入,绝对不能动
│ 写满后切走
▼
② 待归档(ready) ← archive_status 下有 .ready,等待 archive_command 处理
│ 归档成功后改名为 .done
▼
③ 可回收(recycled) ← 检查点已确认不需要,且已归档 → 改名为未来的段号复用
│ 或
▼
④ 被删除(removed) ← 若 wal_recycle 关闭,则直接 unlink删除或改名发生在检查点之后,这是关键:检查点会记录 redo 起点,redo 起点之前的所有 WAL 都不再需要(除非还要归档或还有复制槽需要)。
回收的两个门槛
一个段文件能不能被回收,必须同时满足:
| 门槛 | 条件 | 由谁保证 |
|---|---|---|
| 不再需要重放 | 该段在最近一次检查点的 redo 起点之前 | 检查点进程(checkpointer) |
| 归档已完成 | archive_status 中已是 .done(未开归档则无此要求) | 归档进程(archiver) |
| 不再被复制槽绑定 | pg_replication_slots.restart_lsn 已越过该段 | WAL 发送进程(walsender) |
三者只要有一个不满足,段文件就会持续堆积在 pg_wal。这也是「pg_wal 目录莫名涨到几十 GB」最常见的三个原因。
保留多少:max_wal_size 与 min_wal_size
max_wal_size 与 min_wal_size 控制的是给 WAL 预留的磁盘量,不是「WAL 的硬上限」:
min_wal_size(默认 80MB)
· WAL 目录的"下限水位":即使很闲,也保留这么多段文件供复用
· 避免突发写入时临时创建文件带来抖动
max_wal_size(默认 1GB)
· 检查点的"触发参考":两个检查点之间允许累积的 WAL 量
· 超过它会更频繁地触发检查点,从而让文件尽快进入可回收状态
· 注意:它不阻止 WAL 继续增长,只影响检查点节奏-- 查看当前 WAL 相关配置
SELECT name, setting, unit, short_desc
FROM pg_settings
WHERE name IN ('wal_segment_size', 'min_wal_size', 'max_wal_size',
'wal_keep_size', 'wal_level', 'archive_mode')
ORDER BY name; name | setting | unit | short_desc
-------------------+---------+------+----------------------------------------------------------------------
archive_mode | off | | Allows archiving of WAL files using archive_command.
max_wal_size | 1024 | MB | Sets the WAL size that triggers a checkpoint.
min_wal_size | 80 | MB | Sets the minimum size to shrink the WAL to.
wal_keep_size | 0 | MB | Sets the size of WAL files held for standby servers.
wal_level | replica | | Sets the level of information written to the WAL.
wal_segment_size | 16 | MB | Shows the size of WAL segments.WAL 目录的实时状态
不必登到服务器上 ls,SQL 就能列出 pg_wal 内容:
-- 列出 pg_wal 目录内容(需要超级用户或 pg_monitor 角色)
SELECT name, size, pg_size_pretty(size) AS pretty_size, modification
FROM pg_ls_waldir()
ORDER BY name
LIMIT 8; name | size | pretty_size | modification
----------------------------+----------+-------------+------------------------
000000010000000000000001 | 16777216 | 16 MB | 2026-09-20 09:12:33+08
000000010000000000000002 | 16777216 | 16 MB | 2026-09-20 09:41:07+08
000000010000000000000003 | 16777216 | 16 MB | 2026-09-20 10:05:19+08
000000010000000000000004 | 16777216 | 16 MB | 2026-09-20 10:33:51+08
000000010000000000000005 | 16777216 | 16 MB | 2026-09-20 11:02:44+08
000000010000000000000006 | 16777216 | 16 MB | 2026-09-20 11:20:02+08
000000010000000000000007 | 16777216 | 16 MB | 2026-09-20 11:47:18+08
000000010000000000000008 | 16777216 | 16 MB | 2026-09-20 12:01:05+08配合聚合函数可以直接算出 WAL 目录总占用:
-- WAL 目录占用总量与文件个数
SELECT count(*) AS file_count,
pg_size_pretty(sum(size)) AS total_wal_size
FROM pg_ls_waldir(); file_count | total_wal_size
------------+----------------
64 | 1024 MBPG14 起还提供了 pg_stat_wal 视图,用于观察 WAL 的生成速率:
-- 查看 WAL 生成统计(PG14+)
SELECT wal_records, wal_fpi, wal_bytes, pg_size_pretty(wal_bytes) AS wal_bytes_pretty,
wal_buffers_full, stats_reset
FROM pg_stat_wal; wal_records | wal_fpi | wal_bytes | wal_bytes_pretty | wal_buffers_full | stats_reset
-------------+---------+-----------+------------------+------------------+-------------------------------
128430 | 912 | 19874305 | 19 MB | 37 | 2026-09-20 09:00:00.124511+08wal_records是 WAL 记录条数,wal_fpi是全页写入(Full Page Image)次数。wal_bytes是 WAL 总字节数,这是评估写入压力的第一手数据。wal_buffers_full表示 WAL 缓冲区被写满而被迫刷盘的次数,偏大说明wal_buffers偏小。
相关参数
| 参数 | 默认值 | 生效方式 | 说明 |
|---|---|---|---|
wal_segment_size | 16MB | 仅 initdb | 段文件大小,建库后不可改 |
min_wal_size | 80MB | reload | WAL 目录保留的下限水位 |
max_wal_size | 1GB | reload | 触发检查点的 WAL 累积量参考值 |
wal_keep_size | 0 | reload | 为备库额外保留的 WAL 量(PG13+,取代 wal_keep_segments) |
wal_level | replica | 重启 | 写入 WAL 的信息量:minimal / replica / logical |
wal_buffers | -1(自动) | 重启 | WAL 共享缓冲区大小,自动时约为 shared_buffers/32,上限 16MB |
wal_compression | off | reload | WAL 全页镜像压缩:pglz / lz4 / zstd(PG15+ 支持后两者) |
wal_init_zero | on | reload | 新段文件是否预填零(on 更安全,off 更快) |
wal_recycle | on | reload | 是否复用旧段文件而非删除重建 |
archive_mode | off | 重启 | 是否开启 WAL 归档:off / on / always |
archive_command | 空 | reload | 归档命令,如 cp %p /backup/wal/%f |
archive_library | 空 | reload | 用共享库替代 archive_command(PG13+) |
archive_timeout | 0 | reload | 强制切换段文件的时间上限,保证归档时效性 |
# postgresql.conf
# WAL 目录容量与检查点节奏
min_wal_size = 256MB # 提高下限,减少突发写入时创建文件的抖动
max_wal_size = 4GB # 写入量大的库适当放大,降低检查点频率
# WAL 缓冲区:留 -1 让系统自动按 shared_buffers 推导
wal_buffers = -1
# WAL 压缩:PG15+ 可选 lz4 或 zstd,省磁盘也省网络
wal_compression = lz4
# 归档:archive_command 用 cp 时,路径必须已存在且 pg 用户可写
archive_mode = on
archive_command = 'test ! -f /backup/wal/%f && cp %p /backup/wal/%f'
archive_timeout = 300s # 5 分钟至少切一个段,避免低写入时归档延迟详细说明
用 pg_waldump 直接阅读 WAL
pg_waldump 是官方提供的 WAL 解析工具,能把二进制 WAL 记录翻译成人可读的一行行文本,是排查「某个时刻到底改了什么」的终极手段:
# 查看当前活跃段文件的前 10 条记录
pg_waldump -n 10 $PGDATA/pg_wal/000000010000000000000001rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/01600028, prev 0/01600000, desc: RUNNING_XACTS nextXid 745 latestCompletedXid 744 oldestRunningXid 745
rmgr: Heap len (rec/tot): 78/ 78, tx: 745, lsn: 0/01600080, prev 0/01600028, desc: INSERT off 2 flags 0x00, blkref #0: rel 1663/16384/16385 blk 0
rmgr: Btree len (rec/tot): 72/ 72, tx: 745, lsn: 0/016000D0, prev 0/01600080, desc: INSERT_LEAF off 2, blkref #0: rel 1663/16384/16386 blk 1
rmgr: Heap len (rec/tot): 78/ 78, tx: 745, lsn: 0/01600118, prev 0/016000D0, desc: INSERT off 3 flags 0x00, blkref #0: rel 1663/16384/16385 blk 0
rmgr: Transaction len (rec/tot): 34/ 34, tx: 745, lsn: 0/01600168, prev 0/01600118, desc: COMMIT 2026-09-20 09:12:33.184520 CST每一行的关键字段含义:
| 字段 | 含义 |
|---|---|
rmgr | 资源管理器(Resource Manager),如 Heap(堆表)、Btree(B 树索引)、XLOG |
len (rec/tot) | 记录本身的长度 / 含全页镜像后的总长度 |
tx | 产生该记录的事务 ID |
lsn | 该记录自身的 LSN,即其结束位置 |
prev | 同事务上一条记录的 LSN,可用来串联同一事务的记录链 |
desc | 记录描述,如 INSERT off 2 表示在页内第 2 个槽位插入 |
blkref | 被修改的数据块,格式 rel 表空间OID/数据库OID/关系OID blk 页号 |
blkref 的 rel 1663/16384/16385 与表文件的路径完全对应:1663 是 pg_default 表空间 OID,16384 是数据库目录名,16385 就是 relfilenode:
# 由 blkref 反查实际文件路径
ls -lh $PGDATA/base/16384/16385常用选项:
# 只看 Heap(堆表)相关的记录
pg_waldump --rmgr=Heap -n 20 $PGDATA/pg_wal/000000010000000000000001
# 按 LSN 区间过滤(查看某次操作产生的记录)
pg_waldump --start='0/1600028' --end='0/1600168' $PGDATA/pg_wal/000000010000000000000001
# 统计各资源管理器的记录条数与占比
pg_waldump --stats $PGDATA/pg_wal/000000010000000000000001Type N (%) Record size (%) FPIs (%) ...
Heap 4820 62.11 456320 58.42 120 42.1
Btree 1980 25.51 214560 27.47 88 30.9
Transaction 640 8.25 21760 2.78 0 0.0
Standby 320 4.13 9600 1.23 0 0.0归档进度的观察
归档是否跟上,直接看 pg_stat_archiver:
-- 观察归档进程状态(含失败重试与积压判断)
SELECT archived_count,
failed_count,
pg_walfile_name(last_archived_wal) AS last_archived,
pg_walfile_name(last_failed_wal) AS last_failed,
last_archived_time,
stats_reset
FROM pg_stat_archiver; archived_count | failed_count | last_archived | last_failed | last_archived_time
----------------+--------------+-----------------------------+-------------+------------------------
186 | 2 | 0000000100000000000000BA | 0000000100.. | 2026-09-20 12:01:05+08若 failed_count 持续增长,段文件就会卡在 .ready 状态无法回收,pg_wal 会持续膨胀:
-- 还有多少段文件在等待归档
SELECT count(*) AS pending_archive
FROM pg_ls_dir('pg_wal/archive_status') AS f
WHERE f LIKE '%.ready'; pending_archive
-----------------
412WAL 与数据文件的写入顺序
WAL 的顺序写与数据文件的随机写是两套独立 I/O,这正是 PostgreSQL 依靠 WAL 获得性能的来源:
事务提交
│
① 先在 WAL 缓冲区生成 COMMIT 记录
│
② 提交时把 WAL 缓冲区 fsync 到 pg_wal(顺序写)
│ └─ 只要这一步成功,事务就算持久化 ✔
│
③ 数据页仍在 shared_buffers 里变"脏"(尚未落盘)
│
④ 由 bgwriter / checkpointer 在稍后用随机写刷回数据文件
└─ 即使此刻断电,重启后也能用 WAL 重放恢复所以「pg_wal 里的段文件比数据文件新」是正常且必须的,绝不会出现数据比日志新的情况。
实战示例
示例 1:验证 LSN 与段文件名的换算关系
创建测试表并触发写入,然后对比 LSN 与文件名:
-- 1) 建表并插入数据,产生 WAL
CREATE TABLE wal_demo (
id bigserial PRIMARY KEY,
note text
);
INSERT INTO wal_demo (note)
SELECT 'wal record ' || g
FROM generate_series(1, 5000) AS g;
-- 2) 看当前写入位点与对应文件
SELECT pg_current_wal_lsn() AS cur_lsn,
pg_walfile_name(pg_current_wal_lsn()) AS cur_file;
-- 3) 用 pg_wal_lsn_diff 观察这次写入产生了多少 WAL 字节
SELECT pg_size_pretty(
pg_wal_lsn_diff(pg_current_wal_lsn(), '0/0')::bigint
) AS wal_since_start;
-- 4) 列出 WAL 目录,观察文件是否增加
SELECT count(*) AS file_count, pg_size_pretty(sum(size)) AS total
FROM pg_ls_waldir(); cur_lsn | cur_file | wal_since_start | file_count | total
-----------+------------------------------+-----------------+------------+---------
0/1A2B4C8 | 000000010000000000000001 | 8192 kB | 12 | 192 MB结果解读:0/1A2B4C8 的高位是 0,低位 0x1A2B4C8 除以 16MB(0x1000000)得 1,所以落在段号 00000001 的文件里;这不代表只用了 1 个段,file_count = 12 说明已有 12 个段文件(含复用保留的)。注意 cur_file 会随写入增长而变化,一旦低位超过 0xFFFFFF 就切到 00000002。
示例 2:追踪一次更新到底写了什么
从 WAL 层面看清一次 UPDATE 的完整代价:
-- 1) 记录起点 LSN
SELECT pg_current_wal_lsn() AS start_lsn;
-- 2) 执行一次更新
UPDATE wal_demo SET note = note || ' [updated]' WHERE id = 42;
-- 3) 记录终点 LSN,并算出这次更新产生了多少 WAL
SELECT pg_current_wal_lsn() AS end_lsn,
pg_size_pretty(
pg_wal_lsn_diff(pg_current_wal_lsn(), '0/1A2B000')
) AS wal_generated;更实用的做法是拿到区间后交给 pg_waldump 精确过滤:
# 先记录起点与终点 LSN,再用区间过滤
# 假设起点 0/1A2B000,终点 0/1A2B4C8
pg_waldump --start='0/1A2B000' --end='0/1A2B4C8' \
$PGDATA/pg_wal/000000010000000000000001rmgr: Heap len (rec/tot): 78/ 78, tx: 812, lsn: 0/1A2B050, prev 0/1A2B000, desc: HOT_UPDATE off 20 xid 812 flags 0x20 ; new off 35 xid 812 flags 0x00
rmgr: Heap len (rec/tot): 78/ 78, tx: 812, lsn: 0/1A2B0A8, prev 0/1A2B050, desc: HOT_UPDATE off 21 xid 812 flags 0x20 ; new off 36 xid 812 flags 0x00
rmgr: Transaction len (rec/tot): 34/ 34, tx: 812, lsn: 0/1A2B4C8, prev 0/1A2B0A8, desc: COMMIT 2026-09-20 12:20:11.302914 CST结果解读:
- 看到
HOT_UPDATE说明这次更新走了 HOT(Heap-Only Tuple) 优化——更新后的新版本被放到同页,索引无需改动,代价显著降低。 - 每条
HOT_UPDATE都带new off 35指向新版本槽位,说明行版本是「新槽位 + 旧槽位标记过期」的方式实现的。 - 只有一条
COMMIT记录,说明整条UPDATE语句是一个事务,WAL 写入具备原子性。 - 如果
note列有索引改动,这里会出现Btree的INSERT_LEAF/DELETE记录,WAL 量会显著增加。
示例 3:制造并观察段文件切换
用 pg_switch_wal() 主动切段,观察文件与归档状态:
-- 1) 切段前的 LSN 与文件
SELECT pg_current_wal_lsn() AS before_lsn,
pg_walfile_name(pg_current_wal_lsn()) AS before_file;
-- 2) 主动切段(该动作本身也会写 WAL)
SELECT pg_switch_wal() AS switch_at;
-- 3) 切段后的 LSN 与文件
SELECT pg_current_wal_lsn() AS after_lsn,
pg_walfile_name(pg_current_wal_lsn()) AS after_file;
-- 4) 确认已归档的段文件数量
SELECT archived_count, failed_count FROM pg_stat_archiver; before_lsn | before_file | switch_at | after_lsn | after_file
------------+-------------------------------+-----------+------------+-------------------------------
0/1A2B4C8 | 000000010000000000000001 | 0/1A2B4E0 | 0/1A2B4E0 | 000000010000000000000002结果解读:
pg_switch_wal()返回的switch_at就是新段的起始 LSN,紧接在原 LSN 之后。after_file的段号从01变为02,说明新写入会落到新段文件。- 若
archive_mode = on,此时新出现的段文件会先在archive_status生成.ready,归档成功后变为.done,然后才可能被回收。 - 频繁调用
pg_switch_wal()会让pg_wal里出现大量只写了几字节的段文件,不要把它当作日常操作。
注意事项
wal_segment_size建库后无法修改,只能通过initdb --wal-segsize指定。事后想改必须重建实例或重建备库。- 不要手工删除
pg_wal里的文件,哪怕磁盘告急。删掉正在使用或尚未归档的段文件会导致实例无法启动。
# 错误!会破坏崩溃恢复能力,直接导致实例无法启动
# rm -f $PGDATA/pg_wal/000000010000000000000001
# 正确:先查清是谁占着 WAL,再对症处理-- 查清 WAL 膨胀的原因:活跃复制槽(最常见的元凶)
SELECT slot_name, slot_type, active, restart_lsn,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots
ORDER BY restart_lsn;max_wal_size不是硬上限,它只影响检查点频率。一个长事务、一个不推进的复制槽、一个归档失败的.ready文件,都能让pg_wal远超max_wal_size。wal_level = minimal会跳过部分 WAL 写入,性能最好,但此时无法做时间点恢复(PITR),也不支持复制。生产库不要用。archive_command必须保证幂等且可靠。归档失败会让段文件持续堆积;归档成功但返回了非零退出码,则会导致重复归档与磁盘浪费。.partial文件不必惊慌,它会在恢复时被自动截断到有效长度(wal_init_zero = on时还会被预填零)。wal_recycle = off会不断删除旧文件并创建新文件,在某些文件系统上反而更快,但会失去复用带来的元数据开销节省。
最佳实践
- 把
pg_wal目录监控纳入基础告警:文件数或总大小持续增长,一定是复制槽、归档或长事务出了问题。 - 为
max_wal_size预留足够的磁盘余量:按max_wal_size的 2~3 倍评估pg_wal可能达到的峰值空间。 - 写入量大的库适当放大
max_wal_size(如 4~8GB),检查点更少、性能更稳;对小库保持默认即可。 - 开启
wal_compression(推荐lz4):能显著减少 WAL 量,对全页写入(FPI)尤其有效。 - 生产库始终用
wal_level = replica或更高,不要为了省一点 I/O 牺牲可恢复性。 - 复制槽用完立刻删除,这是
pg_wal失控最典型的根因。 - 归档目录与
pg_wal放在不同磁盘,避免两套顺序写互相争抢 I/O。 - 用
pg_waldump解决争议:当有人问「这条数据到底是什么时候被改的」,WAL 是唯一可信的账本。 - 定期校验归档完整性(
pg_verifybackup/pg_waldump抽查),归档断了却以为没事,是恢复时才发现的最惨场景。 pg_switch_wal()只在需要立即归档时使用(如备份前的切换、低写入库配合archive_timeout),不要轮询调用。
下一节
继续学习:Tablespace(表空间)