Skip to content

PostgreSQL WAL满故障

WAL满故障现象

1. 系统层面

  • 磁盘使用率激增:WAL所在磁盘分区使用率达到100%
  • 系统日志告警:包含"No space left on device"错误信息

2. 数据库层面

  • 写入失败:无法执行任何写操作,包括INSERT、UPDATE、DELETE等
  • 连接问题:新连接可能无法建立
  • 错误信息
    • FATAL: could not write to file "pg_wal/xlogtemp.1234": No space left on device
    • ERROR: could not extend file "pg_wal/000000010000000000000001": No space left on device
    • WARNING: transaction log is full, transaction aborted

WAL满故障诊断

1. 检查WAL目录大小

bash
# 查看WAL目录大小
du -sh /var/lib/postgresql/15/main/pg_wal

# 查看WAL目录下的文件数量
ls -la /var/lib/postgresql/15/main/pg_wal | grep -v "\." | wc -l

# 查看WAL目录下的文件大小
ls -lh /var/lib/postgresql/15/main/pg_wal | sort -k5 -rh | head -n 10

2. 检查WAL配置

sql
-- 查看WAL相关配置参数
SHOW wal_keep_size;
SHOW max_wal_size;
SHOW min_wal_size;
SHOW checkpoint_timeout;
SHOW checkpoint_completion_target;
SHOW archive_mode;
SHOW archive_command;

-- 查看复制槽状态
SELECT slot_name, slot_type, active, pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS wal_diff
FROM pg_replication_slots;

-- 查看WAL归档状态
SELECT * FROM pg_stat_archiver;

3. 检查当前WAL使用情况

sql
-- 查看当前WAL位置
SELECT pg_current_wal_lsn();

-- 查看WAL写入速率
SELECT 
  current_timestamp - interval '5 minutes' AS start_time,
  current_timestamp AS end_time,
  pg_wal_lsn_diff(pg_current_wal_lsn(), pg_wal_lsn_offset(pg_current_wal_lsn(), -5*60*1000000)) AS wal_written,
  pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), pg_wal_lsn_offset(pg_current_wal_lsn(), -5*60*1000000))) AS wal_written_pretty
FROM pg_stat_database
WHERE datname = current_database();

WAL满故障解决措施

1. 紧急处理

清理WAL日志(仅在紧急情况下)

bash
# 注意:此操作非常危险,可能导致数据丢失,仅在无法启动数据库时使用
# 确保已备份重要数据
# 清理旧的WAL日志文件
# 只删除确定已归档或已复制的WAL文件
# 例如,删除所有早于000000010000000000000010的WAL文件
sudo rm -f /var/lib/postgresql/15/main/pg_wal/00000001000000000000000*

删除不活跃的复制槽

sql
-- 查看不活跃的复制槽
SELECT slot_name FROM pg_replication_slots WHERE active = false;

-- 删除不活跃的复制槽
SELECT pg_drop_replication_slot('inactive_slot');

调整WAL归档命令

sql
-- 如果归档命令失败,临时修改为简单的归档命令
ALTER SYSTEM SET archive_command = 'cp %p /archive/%f 2>/dev/null || true';

-- 重新加载配置
SELECT pg_reload_conf();

2. 长期解决方案

调整WAL配置参数

sql
-- 调整WAL大小限制
ALTER SYSTEM SET max_wal_size = '2GB';
ALTER SYSTEM SET min_wal_size = '1GB';

-- 调整WAL保留大小
ALTER SYSTEM SET wal_keep_size = '1GB';

-- 调整检查点参数
ALTER SYSTEM SET checkpoint_timeout = '30min';
ALTER SYSTEM SET checkpoint_completion_target = '0.9';

-- 重新加载配置
SELECT pg_reload_conf();

优化WAL归档

  • 使用可靠的归档工具:如pgBackRest、Barman等
  • 配置归档监控:监控归档成功率,及时发现归档失败
  • 设置合理的归档路径:确保归档目录有足够的空间
  • 定期清理归档日志:根据备份策略定期清理旧的归档日志

优化复制配置

  • 监控复制延迟:定期检查复制延迟,及时发现复制问题
  • 限制复制槽数量:只创建必要的复制槽
  • 使用临时复制槽:对于临时需求,使用临时复制槽
  • 定期清理不活跃的复制槽:设置自动清理机制

WAL满故障监控与告警

1. 系统层面监控

bash
# 监控WAL目录所在磁盘的使用率
df -h /var/lib/postgresql/15/main/pg_wal/..

# 使用iostat监控WAL磁盘的I/O
iostat -x 1 /dev/sda

2. 数据库层面监控

sql
-- 监控WAL使用情况
SELECT 
  pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), pg_wal_lsn_offset(pg_current_wal_lsn(), -1*60*1000000))) AS wal_per_minute,
  pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), pg_wal_lsn_offset(pg_current_wal_lsn(), -60*60*1000000))) AS wal_per_hour,
  pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), pg_wal_lsn_offset(pg_current_wal_lsn(), -24*60*60*1000000))) AS wal_per_day
FROM pg_stat_database
WHERE datname = current_database();

-- 监控复制槽的WAL堆积情况
SELECT 
  slot_name,
  slot_type,
  active,
  pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS wal_pending
FROM pg_replication_slots
ORDER BY wal_pending DESC;

-- 监控WAL归档状态
SELECT 
  archived_count,
  failed_count,
  last_archived_wal,
  last_archived_time,
  last_failed_wal,
  last_failed_time
FROM pg_stat_archiver;

3. 告警配置

Prometheus + Grafana监控

  • 监控指标

    • pg_wal_lsn_diff:WAL使用量
    • pg_replication_slots_wal_pending:复制槽WAL堆积量
    • pg_stat_archiver_failed_count:归档失败次数
    • node_filesystem_avail_bytes:WAL目录所在磁盘的可用空间
  • 告警规则

    • WAL目录使用率超过90%时告警
    • 复制槽WAL堆积超过10GB时告警
    • 归档失败次数超过5次时告警

Zabbix监控

  • 监控项

    • WAL目录大小
    • WAL目录使用率
    • 复制槽数量
    • 复制槽WAL堆积量
    • 归档成功率
  • 触发器

    • WAL目录使用率 > 90%
    • 复制槽WAL堆积量 > 10GB
    • 归档失败次数 > 5

WAL满故障预防措施

1. 合理配置WAL参数

  • 根据业务需求调整WAL大小:对于写入密集型业务,适当增大max_wal_size
  • 设置合理的检查点参数:平衡检查点频率和WAL大小
  • 根据复制需求调整wal_keep_size:避免WAL被过早回收

2. 优化归档策略

  • 使用可靠的归档工具:确保归档过程可靠
  • 配置归档监控:及时发现归档失败
  • 定期清理归档日志:避免归档目录空间不足

3. 优化复制配置

  • 监控复制状态:定期检查复制延迟和复制槽状态
  • 限制复制槽数量:只创建必要的复制槽
  • 清理不活跃的复制槽:避免WAL堆积

4. 定期备份

  • 制定可靠的备份策略:包括全量备份和增量备份
  • 定期测试备份恢复:确保备份可用
  • 根据备份策略清理WAL日志:避免WAL日志无限增长

WAL满故障最佳实践

1. 紧急响应流程

  1. 发现问题:通过监控系统发现WAL满故障
  2. 初步诊断:检查WAL目录大小、WAL配置和复制状态
  3. 紧急处理
    • 如果是复制槽问题,删除不活跃的复制槽
    • 如果是归档问题,临时修改归档命令
    • 如果是WAL配置问题,调整WAL参数
  4. 清理空间:清理旧的WAL日志(谨慎操作)
  5. 验证修复:确认数据库恢复正常写入
  6. 根本分析:分析WAL满的根本原因
  7. 长期优化:制定预防类似问题的措施

2. 长期优化策略

  • 建立WAL监控体系:实时监控WAL使用情况、归档状态和复制状态
  • 定期审查WAL配置:根据业务变化调整WAL参数
  • 优化归档和复制策略:确保归档可靠,复制正常
  • 定期清理不活跃的复制槽:避免WAL堆积
  • 制定合理的备份策略:根据业务需求制定备份策略

常见问题(FAQ)

Q1:什么是PostgreSQL WAL?

A1:WAL(Write-Ahead Logging)是PostgreSQL的预写式日志,用于确保数据一致性和可靠性。所有的修改操作都会先写入WAL日志,然后再写入数据文件。

Q2:WAL满的常见原因有哪些?

A2:WAL满的常见原因包括:

  • 归档失败:归档命令执行失败,导致WAL日志无法被回收
  • 复制槽问题:不活跃的复制槽导致WAL日志无法被回收
  • WAL配置不当:max_wal_size设置过大,或wal_keep_size设置过大
  • 写入量突增:突发的大量写入导致WAL日志快速增长
  • 磁盘空间不足:WAL所在磁盘空间不足

Q3:如何快速解决WAL满故障?

A3:快速解决WAL满故障的方法包括:

  • 删除不活跃的复制槽
  • 临时修改归档命令
  • 调整WAL参数
  • 清理旧的WAL日志(谨慎操作)

Q4:如何预防WAL满故障?

A4:预防WAL满故障的措施包括:

  • 合理配置WAL参数
  • 优化归档策略
  • 优化复制配置
  • 定期备份和清理WAL日志
  • 建立WAL监控和告警体系

Q5:WAL满会导致数据丢失吗?

A5:WAL满本身不会导致数据丢失,但如果处理不当,比如强制删除正在使用的WAL文件,可能会导致数据丢失。因此,在处理WAL满故障时,需要谨慎操作,避免误删重要的WAL文件。

Q6:如何监控WAL使用情况?

A6:可以通过以下方式监控WAL使用情况:

  • 监控WAL目录所在磁盘的使用率
  • 监控WAL写入速率
  • 监控复制槽的WAL堆积情况
  • 监控WAL归档状态
  • 使用Prometheus + Grafana或Zabbix等监控工具建立WAL监控体系

Q7:如何清理PostgreSQL WAL日志?

A7:PostgreSQL会自动清理不再需要的WAL日志,清理条件包括:

  • WAL日志已被归档
  • WAL日志已被所有复制槽接收
  • WAL日志超过了max_wal_size限制

如果需要手动清理WAL日志,需要确保日志已经被归档或不再需要,否则可能导致数据丢失。建议使用PostgreSQL提供的工具或命令进行清理,而不是直接删除文件。