我们常说的数据库中WAL是什么

举报
Jack20 发表于 2025/11/26 17:29:55 2025/11/26
【摘要】 一、先搞懂:WAL 是什么?为什么不能删?WAL 是 PostgreSQL 的 “事务日志”,所有写操作(INSERT/UPDATE/DELETE)都会先写入 WAL,再写入数据文件(data file),核心作用有 3 个:崩溃恢复:数据库意外宕机时,重启后通过 WAL 回放未完成的事务,确保数据一致性(不会丢数据);主从复制:主库的 WAL 日志会同步到备库,备库通过回放 WAL 实现数...

一、先搞懂:WAL 是什么?为什么不能删?

WAL 是 PostgreSQL 的 “事务日志”,所有写操作(INSERT/UPDATE/DELETE)都会先写入 WAL,再写入数据文件(data file),核心作用有 3 个:
  1. 崩溃恢复:数据库意外宕机时,重启后通过 WAL 回放未完成的事务,确保数据一致性(不会丢数据);
  2. 主从复制:主库的 WAL 日志会同步到备库,备库通过回放 WAL 实现数据同步(备库没同步完,主库不会删对应 WAL);
  3. 时间点恢复(PITR):如果开启了归档备份(比如把 WAL 归档到 S3 / 本地),可通过 “基础备份 + WAL 归档” 恢复到任意时间点。
PostgreSQL 默认会自动清理过期的 WAL 文件(已同步到备库、已归档、超过保留策略的文件),pg_wal 暴涨说明 “自动清理” 被卡住了,而非 WAL 本身是 “垃圾”。

二、pg_wal 暴涨的 5 个常见原因(对应排查步骤)

结合你的场景(运行半年、数据没增加),WAL 堆积大概率是以下原因,按优先级排查:

1. 主从复制延迟 / 备库异常(最常见)

如果数据库是主从架构,主库会保留备库未同步的 WAL 文件。如果备库宕机、网络中断、同步速度跟不上,主库会一直保留这些 WAL,直到备库同步完成或超过wal_keep_size限制。

排查命令(主库执行):

-- 查看备库同步状态
SELECT 
  client_addr AS 备库IP,
  state AS 同步状态,
  sent_lsn, write_lsn, flush_lsn, replay_lsn,  -- LSN是WAL日志的位置标记
  now() - write_time AS 写入延迟,
  now() - replay_time AS 回放延迟
FROM pg_stat_replication;

  • 如果state不是streaming(比如down):备库异常,需重启备库或修复网络;
  • 如果replay_lsn < sent_lsn:备库有同步延迟,需检查备库资源(CPU/IO 是否满)、是否有慢查询阻塞回放。

2. 归档备份失败(开启了 WAL 归档但没成功)

如果配置了archive_command(将 WAL 归档到备份存储),但归档命令执行失败(比如备份存储满、权限不足、网络问题),PostgreSQL 会认为 “WAL 还没归档完成”,不会清理,导致堆积。

排查命令:


-- 查看归档状态
SELECT 
  archiver,  -- 归档进程状态(running=正常,failed=失败)
  last_archived_wal,  -- 最后一次成功归档的WAL文件
  last_archived_time, -- 最后归档时间
  failed_count,  -- 归档失败次数
  last_failed_wal,  -- 最后失败的WAL文件
  last_failed_time  -- 最后失败时间
FROM pg_stat_archiver;

archiver=failedfailed_count>0:需修复archive_command(比如检查备份路径权限、存储是否可用)。

3. 长事务 / 空闲事务阻塞

PostgreSQL 的 WAL 清理依赖 “事务 ID 推进”,如果存在长时间未结束的事务(比如运行几小时的查询)或空闲事务(连接没关闭,事务没提交 / 回滚),会导致旧的 WAL 文件无法回收(因为要保证事务能看到一致性快照)。
-- 查看运行超过1小时的事务(重点看idle in transaction状态)
SELECT 
  pid,
  usename,
  datname,
  state,
  wait_event,
  now() - query_start AS 运行时长,
  query
FROM pg_stat_activity
WHERE 
  (state = 'idle in transaction' OR state = 'active')
  AND now() - query_start > '1 hour'::interval
ORDER BY 运行时长 DESC;

若有长时间运行的事务:需评估是否可以终止(SELECT pg_terminate_backend(pid);),避免阻塞 WAL 回收。

4. 配置参数不当

关键参数设置不合理,会导致 WAL “过度保留”:
  • wal_keep_size:主库额外保留的 WAL 大小(默认 0),若设太大(比如 10GB),即使备库同步完成,主库仍会保留该大小的 WAL;
  • max_wal_size:WAL 段的最大总大小(默认 16GB),超过会触发检查点(Checkpoint),但如果归档 / 同步卡住,这个参数也无法限制堆积;
  • min_wal_size:WAL 的最小保留大小(默认 80MB),影响检查点触发后的 WAL 回收。

5. 手动备份未正常结束

如果执行过pg_start_backup()手动备份,但没执行pg_stop_backup(),PostgreSQL 会认为 “备份还在进行”,一直保留备份期间产生的所有 WAL,导致暴涨。

-- 查看是否有未结束的备份
SELECT * FROM pg_stat_backup;

  • 若有未结束的备份:需执行pg_stop_backup()终止(如果备份已完成)。

三、解决步骤:先紧急清理(避免磁盘满),再长期控制

第一步:紧急清理(线上优先操作)

目标是快速回收 WAL 空间,避免磁盘耗尽,需先排查并解决上述 “清理阻塞原因”:

1. 先解决阻塞因素(关键!否则清理后还会堆积)

  • 若备库异常:重启备库、修复网络,等待replay_lsn追上sent_lsn(主从同步完成);
  • 若归档失败:修复archive_command(比如更换归档路径、清理备份存储空间),执行SELECT pg_switch_wal();触发 WAL 切换,让归档进程重新尝试归档;
  • 若有长事务:终止长时间运行的空闲事务或慢查询(pg_terminate_backend(pid));
  • 若备份未结束:执行pg_stop_backup()

2. 手动触发 WAL 清理(阻塞因素解决后)


-- 1. 切换WAL日志(生成新的WAL段,让旧段进入可回收状态)
SELECT pg_switch_wal();

-- 2. 手动触发检查点(加速WAL回收,检查点会将WAL中的数据刷到数据文件)
CHECKPOINT;

-- 3. 查看可回收的WAL文件(确认清理是否生效)
SELECT pg_walfile_name(pg_current_wal_insert_lsn()) AS current_wal;  -- 当前正在使用的WAL

执行后,PostgreSQL 会自动删除 “已同步、已归档、非当前使用” 的 WAL 文件,pg_wal 目录大小会快速下降。

3. 极端情况:磁盘即将满(紧急释放空间)

如果磁盘已不足 5%,可临时移动部分旧 WAL 文件到其他存储(仅当确认这些文件已同步到备库 + 已归档):

# 1. 查看当前正在使用的WAL文件(主库执行SQL)
SELECT pg_walfile_name(pg_current_wal_insert_lsn()) AS current_wal;  -- 比如:0000000100000000000000A1

# 2. 进入pg_wal目录(路径:$PGDATA/pg_wal)
cd /var/lib/postgresql/data/pg_wal

# 3. 移动非当前使用的旧WAL文件到临时目录(保留当前WAL和最近1-2个文件,避免误删)
mkdir -p /tmp/pg_wal_backup
mv 000000010000000000000000 0000000100000000000000A0 /tmp/pg_wal_backup/  # 排除当前WAL(A1)

# 4. 触发清理,确认空间释放
psql -U postgres -c "CHECKPOINT;"
df -h  # 查看磁盘空间是否恢复

注意一下下:移动的文件需保留 7 天以上,确认数据库正常后再删除,避免后续需要恢复。

第二步:长期控制 WAL 大小(避免复发)

通过配置优化,让 PostgreSQL 自动控制 WAL 大小,无需手动干预:

1. 调整核心配置参数(postgresql.conf)

编辑postgresql.conf(路径:$PGDATA/postgresql.conf),修改以下参数,重启数据库生效(或ALTER SYSTEM SET动态生效):

# 1. 控制主库保留的WAL大小(仅主从架构需要,默认0)
# 建议设为备库同步所需的最大延迟对应的WAL大小(比如备库最多延迟1小时,按写入速度估算)
# 例:若每小时写入1GB WAL,设为2GB(留缓冲),超过后主库会主动删除旧WAL(备库同步延迟会报错,需监控)
wal_keep_size = 2GB  

# 2. 控制WAL段的最大总大小(默认16GB,根据磁盘空间调整)
# 超过该大小会触发检查点,将WAL数据刷到数据文件,之后可回收旧WAL
max_wal_size = 8GB  # 若磁盘较小,可设为4-8GB(避免单轮WAL占满磁盘)

# 3. 最小WAL保留大小(默认80MB,无需改)
min_wal_size = 80MB

# 4. 归档配置(开启归档时必须确保成功,否则会堆积)
# 示例1:归档到本地目录(需提前创建目录,权限700,属主postgres)
archive_command = 'cp %p /path/to/archive/%f'  # %p=当前WAL路径,%f=WAL文件名
# 示例2:归档失败时重试(避免单次失败导致堆积)
archive_command = 'cp %p /path/to/archive/%f || sleep 5; cp %p /path/to/archive/%f'
# 示例3:归档成功后删除原文件(仅非主从架构,主从架构需保留供备库同步)
# archive_command = 'cp %p /path/to/archive/%f && rm %p'

# 5. 检查点间隔(默认5分钟,可缩短,让WAL更频繁回收)
checkpoint_timeout = 5min  # 触发检查点的时间间隔
checkpoint_completion_target = 0.9  # 检查点完成时间占间隔的比例(避免IO峰值)

  • 动态生效命令(不用重启数据库):
  • ALTER SYSTEM SET wal_keep_size = '2GB';
    ALTER SYSTEM SET max_wal_size = '8GB';
    SELECT pg_reload_conf();  -- 重载配置
    


2. 主从架构优化

  • 用 “复制槽” 替代wal_keep_size:复制槽会自动跟踪备库的同步进度,主库只保留备库未同步的 WAL,避免过度保留(推荐 PostgreSQL 10 + 使用):
  • -- 主库创建复制槽(备库连接时指定该槽)
    SELECT pg_create_physical_replication_slot('repl_slot');
    -- 备库连接字符串添加复制槽:host=主库IP port=5432 user=repl password=xxx dbname=xxx replication_slot=repl_slot
    


  • 监控备库同步延迟:设置告警(比如延迟超过 30 分钟告警),避免备库异常导致 WAL 堆积。

3. 归档备份优化

  • 定期清理归档的 WAL 文件:归档的 WAL 文件用于 PITR,建议保留 “基础备份 + 7 天 WAL”(根据业务备份策略调整),超过期限的归档文件可自动删除(比如用脚本定期清理);
  • 确保归档存储可用:监控归档目录的磁盘空间,避免存储满导致归档失败。

4. 日常监控

添加以下监控指标,提前发现 WAL 堆积风险:
  1. pg_wal 目录大小:设置阈值(比如超过 max_wal_size 的 1.5 倍告警);
  2. 备库同步延迟:replay_lsnsent_lsn的差距(超过 1GB 告警);
  3. 归档状态:pg_stat_archiverfailed_count(大于 0 告警);
  4. 长事务:运行超过 30 分钟的事务(告警并排查)。

四、常见的小误区(避坑哦!)

  1. 误区 1:直接删除 pg_wal 文件 → 后果:数据库崩溃,无法启动,可能丢数据;
  2. 误区 2:把wal_keep_size设为 0 就万事大吉 → 主从架构下,备库短暂延迟可能导致同步失败,需结合复制槽使用;
  3. 误区 3:修改max_wal_size就能限制堆积 → 若归档 / 同步卡住,max_wal_size无效,核心是确保清理机制正常;
  4. 误区 4:禁用 WAL → 绝对禁止!PostgreSQL 无法禁用 WAL(除非单用户模式维护),禁用后数据无保障。

总结一下下

  1. pg_wal 文件不能直接删,堆积是 “清理机制阻塞” 导致(主从延迟、归档失败、长事务等);
  2. 紧急处理:先排查并解决阻塞因素,再执行pg_switch_wal()+CHECKPOINT触发清理;
  3. 长期控制:通过wal_keep_size+max_wal_size配置,优化主从 / 归档,监控关键指标;
  4. 核心原则:确保 WAL 的 “同步(主从)” 和 “归档(备份)” 正常,PostgreSQL 会自动清理过期 WAL,无需手动干预。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。