当前位置: 首页 > news >正文

一次深夜告警复盘:我们是如何用pg_basebackup + 归档搞定PostgreSQL备库WAL丢失的

深夜告警:PostgreSQL备库WAL同步中断的实战救援记录

凌晨2:17,手机突然响起刺耳的告警铃声。监控系统显示生产环境的PostgreSQL备库同步状态异常,pg_stat_replication视图中的replay_lag字段已经飙升至3小时以上。作为当晚的值班工程师,我立刻从床上弹起来,打开笔记本开始排查这个突如其来的故障。

1. 故障现象与初步诊断

登录备库服务器后,首先检查PostgreSQL日志,发现了关键错误信息:

2024-03-15 02:05:23.417 UTC [28761] FATAL: could not receive data from WAL stream: ERROR: requested WAL segment 0000000100000000000000AB has already been removed

这个错误表明备库请求的WAL日志段在主库上已经被清理。进一步查看主库的pg_wal目录,确认确实缺少从0000000100000000000000AB开始的连续几个WAL文件。

关键排查步骤:

  1. 检查主备库的WAL位置差异:

    -- 在主库执行 SELECT pg_current_wal_lsn(); -- 在备库执行 SELECT pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();
  2. 确认主库的WAL保留配置:

    SHOW wal_keep_segments; SHOW max_wal_size;
  3. 查询最近的大型事务:

    SELECT pid, usename, application_name, backend_start, xact_start, query_start, state_change, wait_event_type, wait_event, state, backend_xmin, query FROM pg_stat_activity WHERE backend_type = 'client backend' ORDER BY xact_start DESC;

排查发现,当晚23:00左右有一个批量数据导入作业,处理了近500万条记录。这个长时间运行的事务产生了大量WAL日志,而备库由于网络带宽限制未能及时同步。

2. 应急决策:为什么选择pg_basebackup重建

面对WAL缺失的情况,通常有几种恢复方案:

方案优点缺点适用场景
增大wal_keep_segments简单快速治标不治本,可能再次出现同样问题临时应急,测试环境
使用归档日志恢复可靠,能精确恢复需要提前配置好归档已启用归档的环境
pg_basebackup重建彻底解决问题耗时较长,需要停机数据量适中,允许维护窗口
启用复制槽预防性措施需要提前配置长期解决方案

我们环境已经配置了WAL归档,但考虑到:

  1. 缺失的WAL段较多,从归档恢复耗时可能超过维护窗口
  2. 备库本身没有承担关键读负载
  3. 需要彻底解决类似问题

最终决定采用pg_basebackup重建备库+归档追平的组合方案。这个选择基于以下考量:

  • 虽然重建需要时间,但能确保数据一致性
  • 归档日志可以保证不丢失任何数据变更
  • 重建过程可以并行进行,减少停机时间

3. 详细恢复操作流程

3.1 准备工作

首先确保主库归档功能正常:

# 检查归档状态 psql -h primary -U postgres -c "SELECT name, setting FROM pg_settings WHERE name LIKE '%archive%';" # 手动触发WAL切换并检查归档 psql -h primary -U postgres -c "SELECT pg_switch_wal();" ls -l /archive/path/

准备备库重建环境:

# 停止备库服务 sudo systemctl stop postgresql-12 # 备份重要配置文件 cp /var/lib/pgsql/12/data/postgresql.conf /tmp/ cp /var/lib/pgsql/12/data/recovery.conf /tmp/ 2>/dev/null || echo "No recovery.conf"

3.2 使用pg_basebackup获取基础备份

在主库上创建专用复制用户(如尚未配置):

CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'securepassword'; ALTER ROLE replicator CONNECTION LIMIT 3;

在备库节点执行基础备份:

# 清空数据目录(先确认备份了配置文件) rm -rf /var/lib/pgsql/12/data/* # 执行基础备份 pg_basebackup -h primary -U replicator -p 5432 -D /var/lib/pgsql/12/data \ -P -v -R -X stream -c fast -C -S standby1 # 恢复配置文件 cp /tmp/postgresql.conf /var/lib/pgsql/12/data/

关键参数说明:

  • -R:自动创建recovery.conf(PG12+集成到postgresql.conf)
  • -X stream:在备份期间同时流式传输WAL
  • -c fast:使用快速检查点
  • -C -S standby1:同时创建复制槽,避免未来WAL丢失

3.3 配置归档恢复

编辑postgresql.conf配置归档恢复:

restore_command = 'cp /archive/path/%f "%p"' archive_cleanup_command = 'pg_archivecleanup /archive/path %r' recovery_target_timeline = 'latest'

对于PostgreSQL 12及以上版本,配置standby.signal文件:

touch /var/lib/pgsql/12/data/standby.signal

3.4 启动备库并监控进度

启动备库服务:

sudo systemctl start postgresql-12

实时监控恢复进度:

tail -f /var/lib/pgsql/12/data/log/postgresql-$(date +%a).log # 在备库查询恢复状态 psql -c "SELECT pg_is_in_recovery(), pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(), pg_wal_lsn_diff( pg_current_wal_lsn(), pg_last_wal_replay_lsn()) AS lag_bytes;"

4. 预防措施与经验总结

这次故障的根本原因是缺乏对大型事务的监控和防护机制。事后我们实施了以下改进:

  1. 复制槽标准化配置

    -- 主库创建永久复制槽 SELECT * FROM pg_create_physical_replication_slot('standby1_slot'); -- 备库配置 primary_slot_name = 'standby1_slot'
  2. 大事务监控系统

    -- 部署监控脚本,检测长时间运行的事务 SELECT pid, now() - xact_start AS duration, query FROM pg_stat_activity WHERE state IN ('idle in transaction', 'active') AND now() - xact_start > interval '5 minutes';
  3. WAL归档增强

    • 实现多级归档保留策略(本地7天+S3 30天)
    • 部署定期归档完整性检查脚本
  4. 备库同步告警优化

    • 设置多级阈值告警(1小时警告,3小时严重)
    • 增加备库延迟与主库WAL保留量的关联检查

关键教训:

  • 对于批量操作,应该拆分为小事务分批提交
  • 生产环境必须配置复制槽或足够的WAL保留
  • 定期验证归档完整性和恢复流程
  • 维护文档化的应急操作手册

这次深夜故障处理让我深刻体会到,数据库高可用不是简单的配置问题,而是需要从架构设计、监控预警到应急响应全链条的周密考虑。特别是对于PostgreSQL这类复杂系统,理解其WAL机制和复制原理,才能在关键时刻做出正确的决策。

http://www.jsqmd.com/news/740866/

相关文章:

  • Graphify-DotNet:AI 驱动的 .NET 代码知识图谱构建工具
  • 终极指南:如何让魔兽争霸3在现代电脑上焕发新生
  • 千问 LeetCode 2009.使数组连续的最少操作数 Python3实现
  • [具身智能-538]:人类:硅基世界的 “建设者”,还是 “打工人”?
  • Windows 一键安装 OpenClaw 教程 零代码无命令部署
  • 链下数据索引工具sub-bridge:构建可靠链上事件监听与处理管道
  • 5分钟彻底美化你的VLC播放器:5款VeLoCity皮肤终极指南
  • 2. BundleSDF的虚拟环境搭建
  • 告别机械电位器!用STM32和MCP4017打造你的智能亮度调节模块(教程+源码)
  • 115proxy-for-kodi:在Kodi中实现115网盘视频流式播放的技术实现
  • 通过 curl 命令直接测试 Taotoken 聊天补全接口的完整步骤
  • 别再傻傻改元组了!Python新手必懂的3种‘不可变’数据替换技巧(附代码对比)
  • 告别虚拟机卡顿:实测2015款iMac用Rufus直装Win11双系统,驱动与5K分辨率完美设置指南
  • Java String 类深入解析
  • 如何快速成为斗地主高手:DouZero AI助手完整使用指南
  • 从零搭建GPU监控看板:用Python脚本+nvidia-smi定时抓取数据并可视化
  • 从色卡到代码:手把手教你用Python实现CIE 1931色度图转换(附完整代码)
  • 告别symbolicatecrash:Xcode 13.3后,用atos和CrashSymbolicator.py高效解析iOS崩溃日志
  • DBA不会告诉你的事:90%性能问题源于这5个SQL错误
  • 多平台内容矩阵分发系统 核心模块技术实现与技术选型详解
  • 深入RTA-OS内核:手把手教你配置ETAS ISOLAR多核工程的中断(Category1 vs Category2详解)
  • 从用量看板观察不同模型调用的 token 消耗与成本分布
  • 1 7.4.4 PPPoE 上网配置(拨号 → 新连接 → 宽带 PPPoE)
  • 3分钟上手:N_m3u8DL-CLI-SimpleG视频下载终极指南
  • Python分布式训练配置终极检查表(含NCCL_TIMEOUT、TF_CPP_MIN_LOG_LEVEL、RANK/WORLD_SIZE等11个关键环境变量避雷解析)
  • Windows HEIC缩略图完整教程:让资源管理器完美预览iPhone照片
  • 滴滴测开面试复盘:从两道烧脑的智力题到‘猜数字’算法,我的真实闯关记录
  • 网状Meta分析结果怎么看?手把手教你解读gemtc输出:异质性检验、节点分割与SUCRA排序图
  • 利用Taotoken模型广场为你的应用场景选择最合适的大模型
  • 【RAG】【ingestion03】摄取管道与文档管理示例