Skip to content

PostgreSQL 备份与高可用

PostgreSQL 的备份恢复和高可用围绕 WAL 展开。WAL 既能做崩溃恢复,也能做流复制和时间点恢复。

学习目标

学完本页,你要能回答:

问题要掌握的原理
pg_dumppg_basebackup 有什么区别逻辑备份导出对象和数据,物理备份复制数据库文件
为什么 PITR 需要基础备份加 WAL基础备份提供起点,WAL 把数据库推进到目标时间点
为什么流复制会有延迟从库要接收 WAL、写入 WAL、重放 WAL,每一步都可能慢
同步复制是不是绝对不丢数据要看同步级别、确认位置、网络和故障场景
备份和高可用有什么区别高可用解决故障切换,备份解决误删、误更新和灾难恢复
生产怎么设计 RPO/RTO根据业务能丢多久数据、能停多久服务倒推备份和复制策略

零基础先理解 WAL

WAL 是 Write-Ahead Logging,意思是“数据页真正刷盘前,先把修改日志写到 WAL”。这样即使数据库宕机,只要 WAL 已经落盘,就能在重启时把已提交事务重放回来。

mermaid
flowchart TD
    A["业务执行 insert/update/delete"] --> B["生成 WAL 记录"]
    B --> C["WAL 先刷盘"]
    C --> D["事务可以提交"]
    D --> E["数据页稍后刷盘"]
    E --> F{"宕机后重启"}
    F --> G["根据 WAL 重放已提交修改"]

备份、高可用、PITR 都围绕 WAL 展开:

能力WAL 的作用
崩溃恢复重放宕机前已提交但未刷入数据文件的修改
流复制主库把 WAL 发给从库,从库重放 WAL
时间点恢复恢复基础备份后,回放 WAL 到指定时间
审计排查通过时间线和 LSN 判断恢复位置和复制延迟

备份类型

类型工具适合
逻辑备份pg_dump单库、单表、迁移
物理基础备份pg_basebackup整实例恢复、主从搭建
WAL 归档archive_mode时间点恢复

逻辑备份和物理备份区别

对比逻辑备份 pg_dump物理备份 pg_basebackup
备份内容SQL/对象定义/数据逻辑内容数据目录里的物理文件
恢复粒度库、schema、表更灵活通常恢复整个实例或集群
跨版本迁移更适合受版本和平台限制更多
大库速度通常较慢通常更适合大库
PITR单独不支持完整 PITR配合 WAL 支持 PITR
典型用途迁移、导出单表、测试数据容灾、搭建从库、整库恢复

选择原则:

  1. 小库迁移、单表导出、跨版本升级,优先 pg_dump
  2. 大库整实例备份、主从搭建、时间点恢复,优先物理基础备份加 WAL。
  3. 核心生产库不要只做 pg_dump,因为恢复窗口和恢复完整性可能不满足要求。

pg_dump

备份单库:

bash
pg_dump -h 127.0.0.1 -U app -d app_db -Fc -f app_db.dump

恢复:

bash
pg_restore -h 127.0.0.1 -U app -d app_db app_db.dump

-Fc 是自定义格式,恢复时更灵活。

常见参数:

参数作用
-Fc自定义格式,支持 pg_restore 灵活恢复
-j并行备份或恢复,适合较大库
--schema只备份某个 schema
--table只备份某张表
--data-only只导数据
--schema-only只导结构

商业场景:如果误删的是一张配置表,可以从昨天的逻辑备份中恢复到临时库,再导出目标表数据回灌;但如果要恢复 10:23:15 前的全库状态,pg_dump 单独不够,需要 PITR。

物理基础备份

pg_basebackup 会复制主库的数据目录,并记录备份开始和结束所需的 WAL 位置。

示例:

bash
pg_basebackup \
  -h 10.0.0.10 \
  -U repl \
  -D /data/pg_basebackup \
  -Fp \
  -Xs \
  -P

参数含义:

参数说明
-D备份输出目录
-Fpplain 格式,直接输出数据目录结构
-Xs通过流方式包含备份期间需要的 WAL
-P显示进度

为什么备份过程中还要处理 WAL?因为备份复制数据文件需要时间,复制期间业务还在写。不同数据文件可能来自不同时间点,需要 WAL 把它们恢复到一致状态。

mermaid
flowchart TD
    A["开始基础备份"] --> B["记录起始 LSN"]
    B --> C["复制数据文件"]
    C --> D["业务仍在写入并产生 WAL"]
    D --> E["记录结束 LSN"]
    E --> F["保存备份期间 WAL"]
    F --> G["恢复时回放 WAL 到一致点"]

时间点恢复 PITR

PITR 依赖基础备份 + WAL。

mermaid
flowchart TD
    A["基础备份"] --> B["持续归档 WAL"]
    B --> C["发生误删"]
    C --> D["恢复基础备份到临时实例"]
    D --> E["回放 WAL 到误删前"]
    E --> F["校验并导出数据"]

更完整的 PITR 思路:

  1. 先有一个可用的物理基础备份。
  2. 从基础备份开始之后,WAL 持续归档。
  3. 发生误删、误更新或数据损坏时,准备一台临时恢复实例。
  4. 还原基础备份。
  5. 配置 restore_command,让 PostgreSQL 能拿到归档 WAL。
  6. 设置 recovery_target_timerecovery_target_lsn
  7. 启动实例,让它回放 WAL 到目标点。
  8. 校验数据,导出需要回补的记录。

示例配置片段:

conf
restore_command = 'cp /backup/wal_archive/%f %p'
recovery_target_time = '2026-07-06 10:24:00+08'
recovery_target_action = 'pause'

recovery_target_action = 'pause' 的好处是:数据库恢复到目标时间后先暂停,方便 DBA 校验是否就是误操作前的位置,而不是直接打开后继续推进。

商业误删恢复流程:

mermaid
flowchart TD
    A["确认误删时间和影响范围"] --> B["选择误删前最近基础备份"]
    B --> C["恢复到临时实例"]
    C --> D["回放 WAL 到误删前"]
    D --> E["业务和 DBA 校验数据"]
    E --> F["导出误删数据"]
    F --> G["主库执行补偿回灌"]
    G --> H["校验业务状态和审计记录"]

不要轻易把生产主库整体回退到误删前。因为误删之后可能还有正常订单、支付、采集任务状态更新,整体回退会丢掉这些正常业务。更常见做法是恢复到临时库,再把被误删的数据补回主库。

流复制

mermaid
sequenceDiagram
    participant P as Primary
    participant W as WAL
    participant S as Standby
    P->>W: 写 WAL
    S->>P: 接收 WAL
    S->>S: 重放 WAL

流复制可以用于读扩展和高可用,但默认仍可能有复制延迟。

流复制的核心链路:

mermaid
flowchart TD
    A["主库事务提交产生 WAL"] --> B["WAL sender 发送 WAL"]
    B --> C["网络传输"]
    C --> D["从库 WAL receiver 接收"]
    D --> E["写入从库 WAL"]
    E --> F["Startup 进程重放 WAL"]
    F --> G["从库数据追上主库"]

复制延迟可能发生在:

阶段延迟原因
主库发送主库压力大,WAL 产生太快
网络传输跨机房网络抖动或带宽不足
从库写 WAL从库磁盘慢
从库重放大事务、DDL、索引维护、从库查询冲突
应用读从库读到旧数据,表现为刚写完查不到

查看复制状态:

sql
select application_name,
       state,
       sync_state,
       sent_lsn,
       write_lsn,
       flush_lsn,
       replay_lsn,
       write_lag,
       flush_lag,
       replay_lag
from pg_stat_replication;

LSN 可以理解为 WAL 位置。sent_lsnwrite_lsnflush_lsnreplay_lsn 分别表示发送、写入、刷盘、重放到哪里。差距越大,延迟越大。

同步复制和异步复制

模式特点
异步复制主库提交不等从库,性能好,可能丢少量数据
同步复制主库提交等待从库确认,一致性更强,延迟更高

同步复制也要分清“等到哪一步”:

级别大致含义影响
remote write从库已写入操作系统缓存延迟较低,但还没保证刷盘
remote flush从库 WAL 已刷盘持久性更强,提交延迟更高
remote apply从库已重放可查询一致性更强,但最慢

不要简单说“同步复制一定不丢数据”。如果同步从库也故障、配置不当、确认级别较弱,或者故障切换流程错误,仍然可能出现数据风险。生产要结合业务 RPO、网络质量和故障演练来设计。

复制槽是什么

复制槽 replication slot 用来告诉主库:某个订阅者或从库还需要哪些 WAL,主库不要过早清理。

优点:

  1. 从库短暂断开后,主库保留它还没收到的 WAL。
  2. 逻辑复制消费者可以可靠消费变更。

风险:

  1. 从库或消费者长期不消费,主库会持续保留 WAL。
  2. WAL 占满磁盘,主库可能故障。

查看复制槽:

sql
select slot_name,
       slot_type,
       active,
       restart_lsn,
       confirmed_flush_lsn
from pg_replication_slots;

商业项目里,复制槽必须监控 WAL 保留量,不能只创建不管。

备份和高可用不是一回事

能力解决什么不能解决什么
备份误删、误更新、灾难后恢复历史数据自动秒级切换
流复制读扩展、主库故障后切换误删会同步到从库
同步复制降低主库故障丢数据风险增加提交延迟,不能替代备份
PITR恢复到具体时间点恢复需要时间
Patroni/repmgr 等 HA 工具自动选主和故障转移不能保证业务无感,也不能代替数据校验

一句话:高可用让系统尽快恢复服务,备份让数据能回到过去。两者都要有。

商业场景

场景建议
核心交易库基础备份 + WAL 归档 + 流复制 + 定期恢复演练
报表查询使用只读从库,避免影响主库
误删恢复临时实例恢复到误删前,再回补
强一致读不要盲目读从库,要考虑复制延迟

RPO 和 RTO 怎么倒推方案

指标含义举例
RPO最多允许丢多少数据核心订单最多丢 0 到 1 分钟
RTO最多允许停多久核心服务 10 分钟恢复,报表 2 小时恢复

方案设计示例:

系统可接受 RPO/RTO建议
支付/订单RPO 接近 0,RTO 分钟级同步或准同步复制、自动 HA、频繁 WAL 归档、强演练
医疗采集任务RPO 数分钟,RTO 30 分钟内异步流复制、WAL 归档、任务幂等补偿
报表库RPO 1 小时,RTO 数小时定期备份、异步复制或离线重建
测试库可丢数据逻辑备份或快照即可

备份策略不是“每天凌晨备一下”,而是业务要求倒推出来的。

生产备份策略示例

项目策略
物理基础备份每天或每周,按库大小和恢复窗口决定
WAL 归档持续归档到独立存储
逻辑备份关键配置表每日导出,方便单表恢复
从库至少一个只读或热备从库
异地副本核心库至少一份异地
恢复演练每月至少恢复到临时环境
监控WAL 归档失败、复制延迟、备份时长、备份大小、磁盘空间

常见坑

后果正确做法
只做备份不演练恢复真事故时发现备份不可用定期恢复到临时环境
把从库当备份误删会同步到从库从库和备份都要有
WAL 归档失败没人知道PITR 链断裂监控归档失败和 WAL 缺口
复制槽长期 inactiveWAL 堆积撑爆磁盘监控 slot 和 WAL 保留量
所有读都走从库刚写完查不到核心读写一致走主库或做延迟感知
大事务导致复制延迟从库长时间追不上拆批、限速、监控 replay lag

面试标准回答

text
PostgreSQL 备份恢复的核心是 WAL。pg_dump 是逻辑备份,适合迁移、单表恢复和中小库导出;pg_basebackup 是物理基础备份,适合整实例恢复和搭建从库。PITR 依赖基础备份加持续归档 WAL,恢复时先还原基础备份,再回放 WAL 到目标时间点。流复制通过主库发送 WAL、从库接收并重放 WAL 实现,只读扩展和高可用都依赖它。异步复制性能好但可能延迟和丢少量数据;同步复制一致性更强但会增加提交延迟。备份和高可用不是一回事,从库不能替代备份,生产必须按 RPO/RTO 设计策略并定期恢复演练。