目录
文章目录
- 目录
-
- [1. 架构总览](#1. 架构总览)
- [2. 环境准备](#2. 环境准备)
- [3. 主库配置](#3. 主库配置)
- [4. 创建复制用户与配置 pg_hba](#4. 创建复制用户与配置 pg_hba)
- [5. 备库搭建(一条命令)](#5. 备库搭建(一条命令))
- [6. 流复制验证](#6. 流复制验证)
- [7. 双机 WAL 归档设计](#7. 双机 WAL 归档设计)
-
- [8.1 原理:standby 归档](#8.1 原理:standby 归档)
- [8.2 为什么双机都归档](#8.2 为什么双机都归档)
- [8.3 备库归档验证](#8.3 备库归档验证)
- [8. 自动化:每日基础备份 + 7 天清理](#8. 自动化:每日基础备份 + 7 天清理)
-
- [9.1 每日基础备份(备库,基于目录名保留 7 天)](#9.1 每日基础备份(备库,基于目录名保留 7 天))
- [9.2 WAL 归档清理(备库)](#9.2 WAL 归档清理(备库))
- [9.3 主库归档清理(同款思路)](#9.3 主库归档清理(同款思路))
- [9. 断档保护:物理复制槽](#9. 断档保护:物理复制槽)
-
- [10.1 问题背景](#10.1 问题背景)
- [10.2 创建槽(主库)](#10.2 创建槽(主库))
- [10.3 备库绑定槽:正确姿势](#10.3 备库绑定槽:正确姿势)
- [10.4 槽上限保险丝](#10.4 槽上限保险丝)
- [10.5 验证绑定成功(主库)](#10.5 验证绑定成功(主库))
- [10. 坑点实录](#10. 坑点实录)
-
- [坑 1:root 属主毁天灭地 ------ 归档目录和数据目录一个都不放过](#坑 1:root 属主毁天灭地 —— 归档目录和数据目录一个都不放过)
- [坑 2:`primary_conninfo` 改完不重启 walreceiver 不生效](#坑 2:
primary_conninfo改完不重启 walreceiver 不生效) - [坑 3:备库到底能不能做 basebackup?](#坑 3:备库到底能不能做 basebackup?)
- [坑 4:脚本漏了 cron 的 PATH](#坑 4:脚本漏了 cron 的 PATH)
- [11. 容灾切换手册](#11. 容灾切换手册)
-
- [12.1 主库故障 → 提升备库](#12.1 主库故障 → 提升备库)
- [12.2 旧主库修好后 → 重建为新备库](#12.2 旧主库修好后 → 重建为新备库)
- [12. 附录:日常检查命令](#12. 附录:日常检查命令)
- 尾声
1. 架构总览
┌─────────────────────┐
│ 主库 pg-node-1 │ 192.168.24.21(读写)
│ /data/postgre/data │
│ archive_mode = on │
│ 归档 → /data/postgre/archive/(gzip,保留 7 天) │
└──────────┬──────────┘
│ 流复制(异步)
│ 槽: standby_slot
│ 延迟 ~1.8ms
┌──────────┴──────────┐
│ 备库 pg-node-2 │ 192.168.24.22(只读)
│ /data/postgre/data │
│ archive_mode = always(standby 归档)
│ 归档 → /data/backups/waldata/(gzip,保留 7 天)
│ 每日 23:00 在备库本机做 pg_basebackup
│ 备份 → /data/backups/wal-basic-backup/backup_YYYYMMDD_HHMMSS/
└─────────────────────┘
关键设计决策:
| 决策 | 取舍 |
|---|---|
| 异步复制 | 容灾场景用手动切换,不追求零丢失;同步复制会拖慢每个提交 |
| 双机各自归档 | 主库归档保 PITR;备库独立归档(archive_mode=always),两台机器互为备份备份源 |
| 从备库做 basebackup | 备份压力不落在主库,主库 io 一点不占用 |
| 每日备份 + 7 天 WAL | 恢复窗口 = 7 天内的任意时间点 |
2. 环境准备
- 两台 RHEL/CentOS 9 系机器(本文以 RHEL 为例),主机名
pg-node-1(主)、pg-node-2(备) - 内网互通:
192.168.24.21、192.168.24.22 - PostgreSQL 14 从 PGDG 仓库安装
bash
# 两台机器都执行
dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
dnf install -y postgresql14-server postgresql14
/usr/pgsql-14/bin/postgresql-14-setup initdb
systemctl enable --now postgresql-14
数据目录默认 /var/lib/pgsql/14/data,本文统一挪到 /data/postgre/data(数据盘独立挂载,更利于规划):
bash
systemctl stop postgresql-14
mkdir -p /data/postgre
cp -a /var/lib/pgsql/14/data /data/postgre/data
rm -rf /var/lib/pgsql/14/data
sed -i "s#/var/lib/pgsql/14/data#/data/postgre/data#g" /usr/lib/systemd/system/postgresql-14.service
systemctl daemon-reload
systemctl start postgresql-14
3. 主库配置
编辑 /data/postgre/data/postgresql.conf:
ini
# ===== 主库 pg-node-1 =====
wal_level = replica # 流复制至少 replica
archive_mode = on # 主库归档:on 即可
archive_command = 'gzip -c %p > /data/postgre/archive/%f.gz && test -f /data/postgre/archive/%f.gz'
max_wal_senders = 10 # 至少 2:一个给流复制,一个给备份
wal_keep_size = 1024MB # 无槽时的兜底保留窗口
max_slot_wal_keep_size = 20GB # 复制槽上限保险丝(见第 9 节)
归档命令拆解:
gzip -c %p:把 WAL 文件(%p= 源文件完整路径)压缩到标准输出> /data/postgre/archive/%f.gz:重定向落到归档目录(%f= WAL 文件名,如00000001000000000000000D)&& test -f /data/postgre/archive/%f.gz:确保文件真实存在- 为什么用
&&而不是;或||:&&短路时 gzip 的错误码原样传给 PostgreSQL(PG 只认退出码);用;会把退出码取成最后一条test的,掩盖真实错误;用||可能被残留文件"救活"造成假成功。
创建归档目录并修正属主权限(这步不做,就是坑点实录里那个 42 次失败的真实现场):
bash
mkdir -p /data/postgre/archive
chown postgres:postgres /data/postgre/archive
chmod 700 /data/postgre/archive
重启使参数生效:
bash
systemctl restart postgresql-14
4. 创建复制用户与配置 pg_hba
bash
su - postgres -c "psql -c \"CREATE ROLE repl_user REPLICATION LOGIN PASSWORD '<REPL_PASSWORD>'\""
/data/postgre/data/pg_hba.conf 追加(按实际网段收紧):
# replication 连接仅允许备库
host replication repl_user 192.168.24.22/32 md5
然后 reload:
bash
su - postgres -c "psql -c 'SELECT pg_reload_conf()'"
5. 备库搭建(一条命令)
主库要把 pg_hba 放开给备库的主机 IP(上一步已做)。 在备库 pg-node-2 上:
bash
# 先把备库的 postgres 服务停掉(如果初始化过)并准备目录
systemctl stop postgresql-14
rm -rf /data/postgre/data/*
# 从主库拉全量基础备份,-R 会生成 standby.signal 并写 primary_conninfo
su - postgres -c "pg_basebackup -h 192.168.24.21 -U repl_user -D /data/postgre/data -Xs -R -P"
# 启动
systemctl start postgresql-14
参数说明:
| 参数 | 作用 |
|---|---|
-h / -U |
指定主库和复制用户 |
-Xs |
备份期间 WAL 通过流传输(不占用主库磁盘,比 -Xf 快) |
-R |
自动生成 standby.signal + 写入 primary_conninfo------这步是"备库身份"的关键 |
-P |
显示进度 |
检查备库数据目录:
bash
ls /data/postgre/data/standby.signal # 存在 = 备库身份正确
cat /data/postgre/data/postgresql.auto.conf # 有 primary_conninfo 行
postgresql.auto.conf说明 :-R生成的primary_conninfo写在 auto.conf 里而不是 postgresql.conf(避免pg_basebackup覆盖配置文件)。以后改连接串用ALTER SYSTEM命令,不要手改这个文件。
6. 流复制验证
主库看复制状态:
sql
select application_name, client_addr, state, sync_state, replay_lag
from pg_stat_replication;
text
application_name | client_addr | state | sync_state | replay_lag
------------------+---------------+-----------+------------+--------------
walreceiver | 192.168.24.22 | streaming | async | 00:00:00.0018
state = streaming 即正常;replay_lag 毫秒级说明备库跟得很紧。
备库看恢复状态:
sql
select pg_is_in_recovery(), pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();
text
t | 15/69212F20 | 15/69212F20
t 表示处于恢复模式,两个 LSN 一致 = 接收即重放,零积压。
7. 双机 WAL 归档设计
8.1 原理:standby 归档
很多教程只教主库归档,忽略了备库。备库在恢复模式下同样可以归档它收到的 WAL ------只要 archive_mode = always(注意:on 不够,备库归档必须 always)。
备库 postgresql.conf:
ini
# ===== 备库 pg-node-2 =====
wal_level = replica
archive_mode = always # 备库归档的关键!
archive_command = 'gzip -c %p > /data/backups/waldata/%f.gz && test -f /data/backups/waldata/%f.gz'
wal_keep_size = 1GB
8.2 为什么双机都归档
- 主库归档:主库出故障、误删数据时,用"最近的 basebackup + 主库归档"做 PITR 恢复主库
- 备库归档 :备库是容灾主力,它归档自己的 WAL 后,
waldata目录成为一部分"离线备份";且每日 basebackup 也是从备库做的------备份集 + WAL 在备库上自成一套 - 两台归档目录互不相干,清理策略各管各的
8.3 备库归档验证
sql
-- 备库上
select archived_count, failed_count, last_archived_wal, last_archived_time from pg_stat_archiver;
确认 failed_count 不再增长。
8. 自动化:每日基础备份 + 7 天清理
9.1 每日基础备份(备库,基于目录名保留 7 天)
备份在没有业务压力的备库本机执行 ------pg_basebackup 连本机(备库)自己,把备库的物理快照打包走,主库完全无感知。
bash
cat > /data/backups/pg_base_backup.sh <<'EOF'
#!/bin/bash
# ================================================================
# 每日基础备份脚本(在备库上运行)
# 产物: /data/backups/wal-basic-backup/backup_YYYYMMDD_HHMMSS/
# base.tar.gz(全量数据)+ pg_wal.tar.gz(备份期间 WAL)
# backup_manifest(完整性清单)
# ================================================================
export PATH=$PATH:/usr/pgsql-14/bin # cron 环境 PATH 常缺 PG 二进制目录,务必加
BACKUP_BASE_DIR="/data/backups/wal-basic-backup" # 备份集根目录
RETENTION_DAYS=7 # 保留天数(必须 >= 能容忍的恢复窗口)
LOG_FILE="/var/log/pg_base_backup.log" # 备份日志
# ---------- 准备工作 ----------
mkdir -p "${BACKUP_BASE_DIR}" "$(dirname "${LOG_FILE}")"
if [ $? -ne 0 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 无法创建备份或日志目录,退出" | tee -a "${LOG_FILE}" >&2
exit 1
fi
# 生成带时间戳的备份目录名,如 backup_20260827_104051
BACKUP_NAME="backup_$(date +%Y%m%d_%H%M%S)"
BACKUP_DIR="${BACKUP_BASE_DIR}/${BACKUP_NAME}"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "${LOG_FILE}"
}
# ---------- 执行备份 ----------
log "开始制作基础备份: ${BACKUP_NAME}"
# 不写 -h/-U = 连接本机(备库自己)。从备库做备份是刻意设计,不是漏写!
pg_basebackup \
-D "${BACKUP_DIR}" \
-Ft -z -P -v \ # -Ft tar 打包,-z gzip 压缩,-P/-v 显示进度
-X stream \ # WAL 走流传输
-c fast >> "${LOG_FILE}" 2>&1 # fast checkpoint 减轻主库压力
if [ $? -eq 0 ]; then
log "基础备份成功完成"
# ---------- 历史备份清理(基于目录名日期,比 find -mtime 更可靠) ----------
log "开始清理 ${RETENTION_DAYS} 天前的旧备份(基于目录名日期)"
cd "${BACKUP_BASE_DIR}" || exit 1
cutoff_date=$(date -d "-${RETENTION_DAYS} days" +%Y%m%d) # 例如 20260820
log "截止日期:${cutoff_date}"
for dir in backup_*; do
[ -d "$dir" ] || continue
# 目录名 backup_20260827_104051 -> 提取 20260827
dir_date=${dir#backup_} # 去掉前缀
dir_date=${dir_date%%_*} # 只取第一个 _ 前的部分,即 YYYYMMDD
# 格式校验:必须为 8 位数字,防止误删
if [[ ! ${dir_date} =~ ^[0-9]{8}$ ]]; then
log "警告:目录名格式异常,跳过 ${dir}"
continue
fi
# YYYYMMDD 字符串直接比较大小 = 日期比较
if [[ "${dir_date}" < "${cutoff_date}" ]]; then
log "删除过期备份目录:${dir}"
rm -rf "${dir}"
fi
done
else
log "基础备份失败!"
exit 1
fi
log "备份任务结束"
echo "----------------------------------------" >> "${LOG_FILE}"
EOF
chmod +x /data/backups/pg_base_backup.sh
cron(备库每天 23:00):
bash
(crontab -l 2>/dev/null; echo "00 23 * * * /bin/bash /data/backups/pg_base_backup.sh") | crontab -
9.2 WAL 归档清理(备库)
bash
cat > /data/backups/pg_clean_wal.sh <<'EOF'
#!/bin/bash
# ================================================================
# WAL 归档清理脚本(在备库上运行,清 /data/backups/waldata)
# 与主库的 clean_archive.sh 各管各的目录
# ================================================================
ARCHIVE_DIR="/data/backups/waldata" # 备库归档目录
RETENTION_DAYS=7 # 保留 7 天
LOG_FILE="/var/log/pg_wal_clean.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
}
# ---------- 前置检查 ----------
if [ ! -d "$ARCHIVE_DIR" ]; then
log "错误:归档目录 ${ARCHIVE_DIR} 不存在,退出。"
exit 1
fi
mkdir -p "$(dirname "$LOG_FILE")"
# ---------- 清理旧 WAL ----------
log "开始清理 ${RETENTION_DAYS} 天前的WAL归档文件"
deleted_count=$(find "$ARCHIVE_DIR" -type f -name "*.gz" -mtime +${RETENTION_DAYS} -print -delete | wc -l)
log "清理完成,共删除 ${deleted_count} 个过期WAL文件"
echo "----------------------------------------" >> "$LOG_FILE"
EOF
chmod +x /data/backups/pg_clean_wal.sh
cron(备库每天 23:30):
bash
(crontab -l 2>/dev/null; echo "30 23 * * * /bin/bash /data/backups/pg_clean_wal.sh") | crontab -
9.3 主库归档清理(同款思路)
bash
mkdir -p /data/postgre/scripts
cat > /data/postgre/scripts/clean_archive.sh <<'EOF'
#!/bin/bash
# 主库归档目录清理:/data/postgre/archive 保留 7 天
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> /var/log/pg_archive_clean.log; }
deleted=$(find /data/postgre/archive -name "*.gz" -mtime +7 -delete | wc -l)
log "清理完成,删除 ${deleted} 个过期归档"
EOF
chmod +x /data/postgre/scripts/clean_archive.sh
# 主库 cron 23:30(如果想与业务备份错开,改 45 23 即可)
(crontab -l 2>/dev/null; echo "30 23 * * * /bin/bash /data/postgre/scripts/clean_archive.sh") | crontab -
务必想清楚删除窗口 :
-mtime +7就是你的 PITR 恢复窗口。保留 7 天 = 能恢复到 7 天前的任意时刻。WAL 文件删除后,对应时间点的数据就永远找不回了。
9. 断档保护:物理复制槽
10.1 问题背景
备库断网几天,重连后主库 pg_wal 里那几天的 WAL 已经被 checkpoint 回收------备库从断点之后再也追不上了 ,只能重新 basebackup。复制槽解决这个问题:主库保证槽所需的 WAL 绝不回收。
10.2 创建槽(主库)
sql
-- 主库
select pg_create_physical_replication_slot('standby_slot');
select slot_name, slot_type, active from pg_replication_slots;
-- 预期: standby_slot | physical | f (绑定前 f 正常)
10.3 备库绑定槽:正确姿势
物理复制槽是由备库的独立参数 primary_slot_name 指定的,不是 primary_conninfo 连接串的参数!
sql
-- 备库
alter system set primary_slot_name = 'standby_slot';
select pg_reload_conf();
注意生效条件 :primary_conninfo / primary_slot_name 的修改不会让正在运行的 walreceiver 重连,必须让它重建连接:
bash
# 备库,任选其一
systemctl restart postgresql-14 # 最干净(备库无业务,重启无感)
# 或只 kill walreceiver 进程,postmaster 会自动拉起新的
pkill -f "postgres.*walreceiver"
10.4 槽上限保险丝
槽有"无人消费"的天然风险:如果备库长期离线,主库 WAL 会一直保留直到撑爆磁盘。PG 13+ 提供上限:
sql
-- 主库
alter system set max_slot_wal_keep_size = '20GB';
select pg_reload_conf();
超过 20GB 后主库开始警告(pg_wal 不再继续为槽保留 WAL),提醒你该去修备库了。
20GB 的精确语义(读者最容易误解的一点):
- 保护范围 = 槽的
restart_lsn→ 主库当前 LSN 之间累计的 WAL 量,不是断线时间 - 在保护范围内(< 20GB):备库断线几天甚至几周都无所谓------重连后自动从断点续传追平,主库归档、备份一切照常,系统完全自愈,零人工干预
- 超出保护范围(> 20GB) :超出部分的原始 WAL 被删,备库追不平,需要重新做一次
pg_basebackup;但归档、备份、PITR 依然完好
注意:超限删除的只是 pg_wal 中为槽保留的原始 WAL,归档目录里的 .gz 在 WAL 产生时就已完成写入,不受任何影响------PITR 恢复能力完好,受影响的仅是失联备库的增量追平能力。
20GB 是字节预算,不是时间预算:阈值与数据库的 WAL 生成速率有关,业务重的库和轻负载的库含义完全不同。自查当前余量:
sql
select slot_name, active,
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)/1024/1024/1024 as gap_gb
from pg_replication_slots; -- gap_gb = 当前容错余量(GB)
再观察归档目录一天的增量(du -sh /data/postgre/archive),按 20GB ÷ 每天 WAL 量 = 容错天数 换算。容错窗口不够时,按业务容忍度调大上限或收紧清理策略。
10.5 验证绑定成功(主库)
sql
select slot_name, slot_type, active, restart_lsn from pg_replication_slots;
-- 预期: standby_slot | physical | t ← active=t 就是绑定成功
绑定后 restart_lsn 会随备库消费推进,主库 WAL 不会净增长。
10. 坑点实录
以下每个坑都是我们从真实环境里踩出来的,按"错误表现 → 根因 → 修复"记录。
坑 1:root 属主毁天灭地 ------ 归档目录和数据目录一个都不放过
表现 1(归档失败)
LOG: archive command failed with exit code 1
DETAIL: The failed archive command was: gzip -c pg_wal/000000010000000000000001 > /data/postgre/archive/000000010000000000000001.gz && test -f ...
sh: /data/postgre/archive/000000010000000000000001.gz: Permission denied
WARNING: archiving write-ahead log file "000000010000000000000001" failed too many times, will try again later
表现 2(备份失败)
pg_basebackup: error: could not get COPY data stream: ERROR: could not open file "./postgresql.conf.bak.20260714": Permission denied
pg_basebackup: removing data directory "/data/backups/wal-basic-backup/backup_20260827_104051"
根因:都是同一个病根------postgres 用户没有文件操作权限:
- 归档目录
mkdir时用了 root 身份(drwxr-xr-x root root)→ 归档进程无法创建.gz→ 每 60 秒重试一次,失败计数一路涨到 42 次 - 数据目录里混进了 root 属主的文件(
postgresql.conf.bak.20260714,-rw------- root root)→pg_basebackup打包时 postgres 进程读不了它 → 整份备份作废并自动删除(原子性:不留半成品)
修复
bash
# ① 归档目录(主/备库各自执行)
chown postgres:postgres /data/postgre/archive
chmod 700 /data/postgre/archive
# ② 数据目录:找出所有非 postgres 属主的文件
find /data/postgre/data -maxdepth 1 ! -user postgres -ls
# 处理:chown + chmod,或直接移出数据目录(推荐)
chown postgres:postgres /data/postgre/data/postgresql.conf.bak.20260714
chmod 644 /data/postgre/data/postgresql.conf.bak.20260714
要点与铁律:
- 报错可区分:目录不存在 →
No such file or directory;存在但没权限 →Permission denied - 修复归档权限后不需要重启,PG 会自动重试归档
- 数据目录和归档目录里严禁 root 属主的任何文件 ------
.bak、.log、README 等一律放目录外面(数据目录里放配置副本是很多人的习惯,恰恰是 basebackup 隐形杀手)
坑 2:primary_conninfo 改完不重启 walreceiver 不生效
primary_conninfo / primary_slot_name 是 SIGHUP 可重载参数,但 walreceiver 不会因为 reload 而断开重连------旧连接会一直用旧配置。改完后必须:
bash
systemctl restart postgresql-14 # 或
pkill -f "postgres.*walreceiver" # postmaster 会自动拉起新进程
坑 3:备库到底能不能做 basebackup?
能! 官方文档明确支持:pg_basebackup can make a base backup from not only the master but also the standby(前提:备库 max_wal_senders、hot_standby 开启且允许 replication 连接,并建议主库 full_page_writes=on)。
从备库做备份是最优实践 :备份的 IO 压力全部落在备库,主库零占用。本文的每日备份脚本就是"备库连备库自己"(不写 -h 就是本机)。
被这个坑骗过的常见过程:看到
pg_basebackup连上备库后 COPY 逻辑正常,反而怀疑"是不是连到主库了"------实际上从备库做备份完全合法。判断连接目标看报错:连备库 时若恢复模式限制会报cannot start backup during recovery;能 COPY 数据就是正常的非恢复模式服务器(主库)或允许备份的备库。
坑 4:脚本漏了 cron 的 PATH
cron 的 PATH 通常只有 /usr/bin:/bin,PG 二进制目录 /usr/pgsql-14/bin 不在其中。脚本开头务必:
bash
export PATH=$PATH:/usr/pgsql-14/bin
否则定时任务会在命令行找不到 pg_basebackup 而静默失败(手动跑正常、cron 跑失败,最迷惑人的一种)。
11. 容灾切换手册
12.1 主库故障 → 提升备库
bash
# 1) 确认主库不可用(多路确认,别误判)
pg_isready -h 192.168.24.21
# 2) 备库提升为主库
su - postgres -c "pg_ctl promote -D /data/postgre/data"
# 或 psql: select pg_promote();
# 3) 确认提升
su - postgres -c "psql -c 'select pg_is_in_recovery();'" # 应为 f
# 4) 应用/连接串切换到 192.168.24.22(业务侧)
切换即成功:新主库的归档目录仍是 /data/backups/waldata(配置原样保留,归档继续工作)。
12.2 旧主库修好后 → 重建为新备库
bash
# 1) 旧主库(数据已过期)停库并清数据目录(别动归档目录!)
systemctl stop postgresql-14
rm -rf /data/postgre/data/*
# 2) 从新主库拉基础备份(-R 自动生成 standby.signal)
su - postgres -c "pg_basebackup -h 192.168.24.22 -U repl_user -D /data/postgre/data -Xs -R -P"
# 3) 启动
systemctl start postgresql-14
4) 在新主库(原备库)上重建槽(旧槽在旧主库上,已随重建作废):
sql
select pg_create_physical_replication_slot('standby_slot');
5) 新备库绑定槽:
sql
alter system set primary_slot_name = 'standby_slot';
select pg_reload_conf();
6) 配置对齐(新备库 = 原主库,归档方向要跟着改):
bash
# 原主库配置是 archive_mode=on + /data/postgre/archive
# 作为备库应改为(与另一台一致):
# archive_mode = always
# archive_command = 'gzip -c %p > /data/backups/waldata/%f.gz && test -f /data/backups/waldata/%f.gz'
7) 验证:
sql
-- 新主库
select application_name, state, replay_lag from pg_stat_replication; -- streaming
select slot_name, active from pg_replication_slots; -- t
12. 附录:日常检查命令
| # | 检查项 | 命令(注意机器) | 正常表现 |
|---|---|---|---|
| 1 | 流复制 | 主库:select application_name, client_addr, state, replay_lag from pg_stat_replication; |
streaming + 毫秒级 |
| 2 | 槽 | 主库:select slot_name, active, restart_lsn from pg_replication_slots; |
active=t |
| 3 | 主库归档 | 主库:select archived_count, failed_count, last_archived_time from pg_stat_archiver; |
failed_count 停止增长 |
| 4 | 备库恢复 | 备库:select pg_is_in_recovery(), pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(); |
t + 两 LSN 一致 |
| 5 | 备库归档 | 备库:select archived_count, failed_count from pg_stat_archiver; |
failed_count 不增长 |
| 6 | 备份集 | 备库:ls -lt /data/backups/wal-basic-backup/ |
最近目录含 base.tar.gz+pg_wal.tar.gz+backup_manifest |
| 7 | 归档目录 | 两台:`ls -lt <归档目录> | head -3` |
尾声
这套方案是一条完整的数据保护链:
主库实时写入 → 流复制到备库(ms 级) → 主/备双机 gzip 归档(7 天)
→ 备库每日 basebackup(7 天) → 任意时间点可恢复
几个最终提醒:
- 恢复演练迟早要做的------备份只做了不练,等于没有。每月挑一天从备份集 + WAL 恢复到测试实例验证一下。
- 清理窗口 = 恢复窗口 ,改
RETENTION_DAYS前先问自己:业务能接受丢多少天的数据? - 本文的
password请全部替换为你的真实密码;.pgpass或ALTER SYSTEM存密码后,配置文件的权限必须 600。