☰
PostgreSQL高可用生产方案:流复制+pgpool+pg_rman全链路实战
2026/11/4 4:57:24 网站建设 项目流程

简介:本资源是一份面向数据库运维工程师与PostgreSQL高可用架构实践者的完整技术方案文档,聚焦PostgreSQL主从流复制与pgpool-II协同构建生产级高可用数据库集群。内容系统覆盖流复制原理(WAL日志实时同步、同步/异步模式对比)、pgpool-II核心功能(连接池管理、自动故障切换、读写分离与负载均衡)及全链路部署实操,包含环境准备、主备库配置、pgpool参数调优、健康检查与故障模拟等关键环节。资源为1个773KB的Word文档(.docx),结构清晰,含四章二十余节,含版本控制表、详细目录、配置命令示例及hosts/sysctl等系统级调优说明,便于按步骤复现与工程落地。目前已有472人学习下载,适合中高级DBA和云原生数据库架构师快速掌握PostgreSQL高可用建设方法论与实操细节。

1. 这套方案不是为“能跑就行”准备的:它专治主库宕机时业务秒挂、读请求压垮单点、备份恢复找不到时间点这三类生产级翻车现场

你手头正赶一个交付项目,客户明确要求“数据库不能停,查询要快,删库要有后悔药”。不是实验室环境下的概念验证,而是明天就要上线、后天就要接受第三方安全审计的真实系统。这时候翻文档看到“流复制+pgpool”,很容易误以为只是把 PostgreSQL 配两台、再加个中间件——但真正带过完整交付的工程师都知道:90% 的失败不发生在配置语法错误,而藏在时钟不同步导致 WAL 重传失败、pgpool watchdog 网络心跳被防火墙静默丢弃、pg_rman 归档路径权限错位引发备份静默中断这些细节里。本方案源自某高校科研平台高并发数据中台的实际部署,覆盖从 RHEL 7.5 离线环境初始化、PostgreSQL 12.2 与 pgpool-II 4.1.1 双版本兼容适配、到 failover 后虚拟 IP 漂移验证的全链路闭环。它不讲“理论上可行”,只写“我亲手在三台物理机上敲过、重启过、断网测试过、误删表后用 pg_rman 精确恢复到故障前 37 秒”的每一步。适合正在做毕设/课设需要可答辩、可演示、可复现的同学,也适合运维同事拿去直接改参数上线——因为所有配置项都标注了“为什么必须这样设”,所有报错都附带“第一眼该看哪行日志”。


2. 总体架构设计:三层结构与四个核心模块的职责边界必须划清

这套高可用方案不是简单堆砌组件,而是按职责分层、按故障域隔离的工程实践。它由数据层(PostgreSQL 主从实例)、代理层(pgpool-II 集群)、运维层(pg_rman 备份体系)构成三层结构,每个层级承担不可替代的确定性职责。很多初学者会把 pgpool 当作“万能胶水”,试图让它既管连接池又管自动切换还管备份调度,结果是监控告警混乱、切换逻辑冲突、备份脚本与 pgpool 运行时目录权限打架。我们严格划分四个核心模块:

  • 流复制模块:仅负责 WAL 日志的实时传输与应用,不参与任何业务路由或连接管理;
  • pgpool 负载模块:仅处理客户端连接分发、读写分离策略执行、连接数队列控制,不触碰 WAL 或归档路径;
  • watchdog 故障检测模块:独立于 pgpool 主进程运行,通过专用心跳端口(默认 9001)和 ARP 探测双重校验节点存活,避免因 pgpool 进程卡死但网络端口仍通导致的脑裂;
  • pg_rman 备份模块:完全离线运行,备份过程不依赖 pgpool 或主从状态,只与 PostgreSQL 归档配置强耦合。

这种划分带来两个硬性好处:一是故障定位极快——当查询变慢,先查 pgpool 日志而非 PostgreSQL 日志;当备份失败,直接看 pg_rman 输出而非 pgpool.conf;二是升级解耦——升级 pgpool 到 4.2 时,只要保持backend_hostname和backend_port不变,流复制和备份模块完全不受影响。

提示:不要在 pgpool.conf 中配置replication_mode = on同时又开启 PostgreSQL 内置流复制。这是典型的设计冲突——pgpool 的复制模式是逻辑复制(需创建复制槽、触发器同步),而本文档采用的是物理流复制(WAL 页级同步),二者底层机制互斥。必须关闭 pgpool 的复制功能,仅启用load_balance_mode = on和master_slave_mode = on。

2.1 数据层:主从实例的物理隔离与角色固化

主库(master)和备库(standby)不是对等节点,而是有严格角色定义的物理实体。主库必须具备以下刚性特征:

  • wal_level = replica(12.2 版本下不可设为logical,否则 standby 无法启动);
  • max_wal_senders >= 10(预留足够连接给 pgpool 的 health check 及 WAL sender);
  • archive_mode = off(物理流复制下禁用归档,避免 WAL 文件被双路径写入导致冲突);
  • synchronous_commit = remote_write(平衡一致性与性能,比on少一次磁盘刷写,比off多一层网络确认)。

备库则必须满足:

  • primary_conninfo指向主库的host=master_ip port=5432 user=replicator password=xxx,且密码明文存储在~postgres/.pgpass中(pgpool 健康检查依赖此文件);
  • recovery_target_timeline = 'latest'(确保故障切换后能自动追最新时间线,避免手动干预);
  • hot_standby = on(允许只读查询,这是 pgpool 读写分离的前提);
  • archive_mode = off(同主库,物理复制不走归档路径)。

关键点在于:主库不承担读流量,备库不接受写请求,所有写操作必须经由 pgpool 路由到主库。这是避免数据不一致的铁律。很多同学在测试时直接psql -h standby_ip执行 INSERT,看似成功,实则触发 standby 的 recovery 模式退出,整个复制链路中断。

2.2 代理层:pgpool 的四类配置文件及其生效优先级

pgpool-II 的配置不是单文件一锤定音,而是由四类配置文件按严格优先级叠加生效。理解这个顺序,是排查“为什么改了 pgpool.conf 却没效果”的关键:

配置文件作用范围修改后是否需重启优先级典型误用场景
pgpool.conf全局行为(负载均衡、健康检查)必须重启最高误将backend_weight设为 0 导致备库永远不被选中
pool_hba.conf客户端连接白名单reload 即可次高忘记添加 pgpool 管理用户pcp的本地访问权限
pool_passwdpgpool 用户密码认证reload 即可中用pg_md5生成密码时未指定-m参数,导致明文存储
failover.sh故障转移自定义脚本无需重启最低脚本中硬编码ifconfig eth0:0 down,但实际网卡名是ens192

特别注意pool_passwd的生成方式。必须使用 pgpool 自带工具,且强制加密:

# 在 pgpool 安装目录下执行(非系统 PATH) ./bin/pg_md5 -m -u pgpool_user /path/to/pgpool.conf

如果直接编辑pool_passwd写入明文密码,pgpool 启动时会静默忽略该用户,所有通过此用户发起的 pcp 命令(如pcp_node_info)均返回authentication failed,但日志中无明确报错,极易陷入“配置没错却连不上”的玄学困境。

2.3 运维层:pg_rman 备份的三个不可妥协前提

pg_rman 不是“装上就能用”的黑匣子,它依赖三个底层前提成立才能可靠工作:

  1. 归档路径必须由 PostgreSQL 进程自身创建并拥有
    错误做法:root 用户mkdir -p /backup/pg_archive后chown postgres:postgres。正确做法是让 PostgreSQL 启动时自动创建:

    -- 在 psql 中执行(主库) ALTER SYSTEM SET archive_command = 'test ! -f /backup/pg_archive/%f && cp %p /backup/pg_archive/%f'; SELECT pg_reload_conf();

    此时 PostgreSQL 以postgres用户身份执行cp,自动创建/backup/pg_archive目录并拥有全部权限。若目录由 root 创建,WAL 归档会因权限不足静默失败,pg_rman show显示no archive files。

  2. 备份目录必须与 PostgreSQL 数据目录物理隔离
    绝对禁止将pg_rman备份目录设在/var/lib/pgsql/12/data/base/下或其子目录。曾有案例:备份目录设为/var/lib/pgsql/12/data/backup,某次VACUUM FULL触发数据文件重写,操作系统将新文件写入同一 inode,导致 pg_rman 备份集包含部分旧块、部分新块,恢复时出现invalid page in block。

  3. recovery.conf(12.x 前)或postgresql.conf(12.x 后)中的restore_command必须指向 pg_rman 的pg_rman get命令
    12.2 版本中,restore_command已移至postgresql.conf:

    # postgresql.conf 中添加(备库) restore_command = 'pg_rman get -a -D /backup/pg_rman -s %f -d %p'

    注意-a参数表示“自动选择最近有效备份”,避免手动指定 backup_id 出错;-s %f是归档文件名,-d %p是目标路径。漏掉-a会导致恢复时提示no backup found for timeline 1。


3. 流复制实现:从 WAL 传输到 standby 启动的七步闭环

流复制的成败,不在pg_hba.conf一行配置,而在 WAL 产生、发送、接收、应用这四个环节的时序咬合。很多同学卡在“备库启动后立即退出”,根本原因是 WAL 传输链路在某个环节断开,而错误日志分散在主库、备库、pgpool 三处。我们按真实执行顺序,拆解为七步闭环,每步附带验证命令和失败现象。

3.1 第一步:主库 WAL 生成与 sender 进程就绪

主库启动后,必须确认walsender进程已就绪,这是流复制的源头:

# 在主库执行 ps aux | grep walsender # 正常输出应包含: # postgres 12345 0.0 0.1 123456 7890 ? S 10:00 0:00 postgres: walsender replicator 192.168.1.10(5432) streaming 0/12345678

若无此进程,检查postgresql.conf:

  • wal_level是否为replica(非minimal);
  • max_wal_senders是否 ≥ 1(至少预留 1 个给 standby);
  • listen_addresses是否包含'*'或主库 IP(localhost不够,standby 需远程连接)。

注意:wal_level = logical在 12.2 中虽支持,但 standby 无法启动,报错FATAL: could not start WAL streaming: ERROR: replication slot "pgpool_slot" does not exist。必须用replica。

3.2 第二步:SSH 免密登录与.pgpass密码文件双保险

pgpool 的健康检查(health_check_period)和pg_rman的远程操作,都依赖 SSH 免密登录。但仅配 SSH 不够,因为psql连接主库时仍需密码。必须双保险:

# 在 pgpool 节点执行(假设 pgpool 与 standby 同机) ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_pgpool -N "" ssh-copy-id -i ~/.ssh/id_rsa_pgpool.pub postgres@master_ip ssh-copy-id -i ~/.ssh/id_rsa_pgpool.pub postgres@standby_ip # 创建 .pgpass(600 权限!) echo "master_ip:5432:*:replicator:replicator_pass" > ~/.pgpass echo "standby_ip:5432:*:replicator:replicator_pass" >> ~/.pgpass chmod 600 ~/.pgpass

常见翻车点:.pgpass权限不是 600,PostgreSQL 会拒绝读取,报错password file "/home/postgres/.pgpass" has group or world access; permissions should be u=rw (0600) or less。

3.3 第三步:pg_basebackup全量克隆与recovery.signal生成

这是备库数据的唯一可信来源。必须用pg_basebackup,禁用rsync或cp:

# 在 standby 节点执行(以 postgres 用户) pg_basebackup -h master_ip -p 5432 -U replicator -D /var/lib/pgsql/12/data -P -R -X stream -C -S pgpool_slot

参数详解:

  • -R:自动生成standby.signal(12.x 后取代recovery.conf);
  • -X stream:同步获取 WAL(避免备份期间新 WAL 丢失);
  • -C:自动创建复制槽pgpool_slot(防止主库 WAL 被清理);
  • -S pgpool_slot:槽名必须与 pgpool.conf 中sr_check_database一致。

若执行后data目录下无standby.signal,说明-R失败,需手动创建:

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

3.4 第四步:备库postgresql.conf关键参数修正

克隆后,必须修改备库配置,否则启动即退出:

# /var/lib/pgsql/12/data/postgresql.conf # 必须修改项(其他保持主库默认) primary_conninfo = 'host=master_ip port=5432 user=replicator password=replicator_pass application_name=standby1' primary_slot_name = 'pgpool_slot' hot_standby = on max_connections = 100 # 必须 ≥ 主库 max_connections,否则 pgpool 健康检查失败

特别注意max_connections:若备库设为 50,主库为 100,pgpool 的health_check_period会因连接数超限被拒绝,日志报connection limit exceeded,但 pgpool 仍显示节点为down。

3.5 第五步:启动备库并验证 WAL 接收

启动后,立刻验证 WAL 是否在流动:

# 在 standby 执行 ps aux | grep walreceiver # 应看到 walreceiver 进程 # 查看最近接收的 WAL 文件 ls -lt /var/lib/pgsql/12/data/pg_wal/ | head -5 # 文件名应持续更新(如 00000001000000000000000A → 00000001000000000000000B) # 检查复制延迟(单位:字节) psql -c "SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn FROM pg_stat_replication;" # write_lsn 与 replay_lsn 差值应 < 1MB,否则存在应用瓶颈

若state为startup,说明 standby 正在回放 WAL,属正常;若为failed,检查pg_log中FATAL: could not connect to the primary server,大概率是primary_conninfo密码错误或防火墙阻断。

3.6 第六步:主库创建复制用户与 pgpool 认证打通

pgpool 需用replicator用户连接主库做健康检查,该用户必须有REPLICATION权限:

-- 在主库 psql 中执行 CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'replicator_pass'; -- 验证 \du replicator -- 输出应含 "Replication"

同时,在主库pg_hba.conf添加:

# TYPE DATABASE USER ADDRESS METHOD host replication replicator 192.168.1.0/24 md5 host all replicator 192.168.1.0/24 md5

reload主库配置后,从 standby 节点测试:

psql -h master_ip -U replicator -d postgres -c "SELECT 1;" # 必须返回 1,否则 pgpool 启动后健康检查全失败

3.7 第七步:流复制状态的黄金三指标

不要只看pg_stat_replication,必须交叉验证三个指标:

指标位置正常值特征异常含义
pg_stat_replicationstate = 'streaming',replay_lsn > 0state = 'catchup'表示追赶中,但超过 5 分钟需警惕
pg_controldataLatest checkpoint location与replay_lsn接近差值 > 10MB 表示 WAL 应用严重滞后
pg_wal_lsn_diff()函数SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) FROM pg_stat_replication;返回值 < 1048576(1MB)为健康

常见问题:pg_wal_lsn_diff返回负数。这是因为replay_lsn是文本型,需显式转换:
SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), '0/12345678'::pg_lsn);
若不转换,PostgreSQL 会尝试字符串比较,结果不可信。


4. pgpool 高可用实现:watchdog、健康检查与 failover 的联动逻辑

pgpool 的高可用不是“配完就自动切换”,而是由watchdog(看门狗)、health_check(健康检查)、failover_command(故障转移脚本)三者精密联动的结果。很多方案失败,是因为只配了failover_command,却忽略了 watchdog 的心跳探测和健康检查的阈值设置。

4.1 watchdog 的双通道心跳机制

watchdog 不是简单的 ping,而是双通道探测:

  • TCP 心跳:向其他 pgpool 节点的wd_ipc_socket_dir(默认/tmp)发送 socket 消息,检测进程存活;
  • ARP 心跳:向虚拟 IP(VIP)发送 ARP 请求,检测 VIP 是否在当前节点响应。

必须同时满足两个条件,节点才被判定为ALIVE。若只通 TCP 但 VIP 不响应,watchdog 会触发vip_ifconfig_cmd执行ifconfig eth0:0 192.168.1.100/24 up抢占 VIP;若只通 ARP 但 TCP 断开,则认为网络分区,进入DEGRADED状态,拒绝新连接。

配置要点:

# pgpool.conf use_watchdog = on wd_hostname = 'pgpool1' # 本节点 hostname wd_port = 9001 wd_heartbeat_port = 9002 delegate_IP = '192.168.1.100' # VIP ifconfig_path = '/sbin/ifconfig' arping_path = '/usr/sbin/arping'

提示:arping_path必须是绝对路径,且arping命令需安装(yum install iputils)。若缺失,watchdog 日志报arping command not found,但进程不退出,导致 VIP 永远不漂移。

4.2 健康检查的四级衰减策略

pgpool 的健康检查不是“一次失败就切”,而是四级衰减:

状态触发条件持续时间后果
DOWN连续health_check_max_retries次失败health_check_retry_delay * 次数节点标记为 down,不再接收请求
DEGRADEDhealth_check_max_retries未达,但失败率 >health_check_timeout动态计算降低backend_weight,减少流量分配
UP连续health_check_max_retries次成功同上恢复 full weight
UNKNOWN初始状态或配置错误永久不参与负载均衡

关键参数:

health_check_period = 10 # 每 10 秒检查一次 health_check_timeout = 20 # 单次检查超时 20 秒 health_check_max_retries = 3 # 连续 3 次失败才 down health_check_retry_delay = 10 # 每次重试间隔 10 秒

这意味着:一个节点真实宕机后,最快10 + 10 + 10 = 30秒被标记为DOWN,最慢10*3 = 30秒(因超时直接判失败)。不要期望秒级切换,这是设计使然。

4.3 failover_command 脚本的原子性保障

failover_command是故障转移的最终执行者,必须满足原子性:要么全部成功,要么全部回滚。典型脚本结构:

#!/bin/bash # /etc/pgpool-II/failover.sh # 参数:$1=failed_node_id $2=new_master_id $3=old_primary_id FAILED_NODE=$1 NEW_MASTER=$2 OLD_PRIMARY=$3 # 1. 记录日志 logger "PGPOOL FAILOVER: node $FAILED_NODE down, promoting node $NEW_MASTER" # 2. 在新主库上执行 promote(12.x 后) sudo -u postgres psql -c "SELECT pg_promote();" -h $(hostname) # 3. 更新 pgpool 的 backend 状态(关键!) # 通知 pgpool 新主库 ID sudo pcp_attach_node -h localhost -U pcp_user -n $NEW_MASTER -w # 4. 清理旧主库的 replication slot(防 WAL 积压) if [ "$OLD_PRIMARY" != "-1" ]; then sudo -u postgres psql -c "SELECT pg_drop_replication_slot('pgpool_slot');" -h $(hostname) fi exit 0

注意:pcp_attach_node必须在pg_promote后执行,否则 pgpool 仍认为旧主库是 master,继续往其发写请求。曾有案例:脚本漏掉此行,导致 promote 后写请求被拒绝,业务报read-only transaction。

4.4 读写分离的 SQL 路由规则

pgpool 的读写分离不是“SELECT 走备库,INSERT 走主库”这么简单,它遵循严格的 SQL 解析规则:

  • 明确写操作:INSERT、UPDATE、DELETE、TRUNCATE、CREATE、DROP、ALTER等 DDL/DML 语句,强制路由到 master;
  • 明确读操作:SELECT语句,若无FOR UPDATE、FOR SHARE、WITH FOR UPDATE子句,且不在事务块中,才可能路由到 standby;
  • 事务内读操作:一旦事务中执行了任何写操作,后续所有SELECT均路由到 master,保证事务一致性。

验证路由:

-- 连接 pgpool(非直连) psql -h 192.168.1.100 -p 9999 -U app_user -d mydb -- 执行 BEGIN; SELECT pg_backend_pid(); -- 返回 master 的 PID INSERT INTO t1 VALUES (1); SELECT pg_backend_pid(); -- 仍返回 master 的 PID,即使此处是 SELECT COMMIT;

若发现SELECT总走 master,检查pgpool.conf:

  • load_balance_mode = on
  • master_slave_mode = on
  • white_function_list = ''(空值表示不限制,若填了nextval, currval等,会强制走 master)

4.5 常见问题:pgpool 启动失败的五大血泪坑

现象 → 原因 → 解决,按发生频率排序:

  1. 现象:pgpool进程启动后立即退出,pgpool.log无有效日志
    原因:pgpool.conf中pid_file路径不存在或权限不足(如/var/run/pgpool/pgpool.pid)
    解决:mkdir -p /var/run/pgpool && chown postgres:postgres /var/run/pgpool

  2. 现象:pcp_node_info返回ERROR: authentication failed
    原因:pool_passwd未用pg_md5 -m生成,或pcp.conf中用户未启用(enable = on)
    解决:重新生成pool_passwd,检查pcp.conf中pcp_user行末尾为md5而非reject

  3. 现象:show pool_nodes显示所有节点status = down
    原因:health_check_user在主库/备库中无对应用户,或.pgpass密码错误
    解决:在主备库均执行CREATE USER health_check WITH PASSWORD 'xxx';,并在.pgpass中添加

  4. 现象:VIP 漂移后,客户端连接192.168.1.100仍超时
    原因:客户端所在网络的交换机未刷新 ARP 缓存,或arping未安装导致 watchdog 无法探测
    解决:在客户端执行arp -d 192.168.1.100清缓存;在 pgpool 节点yum install iputils

  5. 现象:pgpool日志频繁报failed to send packet to backend
    原因:backend_flag配置错误,如BACKEND_FLAG_ALLOW_TO_FAILOVER未设,导致 pgpool 认为节点不可 failover
    解决:backend_flag0 = 'ALLOW_TO_FAILOVER'(主库),backend_flag1 = 'ALLOW_TO_FAILOVER'(备库)


5. pg_rman 备份与恢复:从全量备份到 PITR 时间点恢复的完整链路

pg_rman 不是“备份软件”,而是 PostgreSQL 归档生态的调度器。它的价值不在备份速度,而在精确恢复能力——能恢复到任意事务提交时刻(PITR),这是 mysqldump 等逻辑备份无法做到的。本节聚焦如何构建一条从pg_rman backup到pg_rman restore的零误差链路。

5.1 归档模式的三重校验

归档是否生效,不能只看archive_command配置,必须三重校验:

  1. 主库archive_mode = on且archive_command非空

    SHOW archive_mode; -- must be 'on' SHOW archive_command; -- must not be '(disabled)'
  2. 归档目录存在且 PostgreSQL 可写

    sudo -u postgres touch /backup/pg_archive/test && rm /backup/pg_archive/test # 若报 permission denied,检查 SELinux 或目录 owner
  3. WAL 文件真实生成并归档

    # 手动切换 WAL psql -c "SELECT pg_switch_wal();" # 等待 10 秒 ls -lt /backup/pg_archive/ | head -3 # 应看到新文件,如 `00000001000000000000000B`

注意:pg_switch_wal()在 10.x 后取代pg_switch_xlog(),若用错函数,命令静默失败,无文件生成。

5.2 pg_rman 初始化与全量备份

初始化是备份的前提,必须在主库执行:

# 创建备份目录(由 pg_rman 自动管理) mkdir -p /backup/pg_rman # 初始化(指定 PostgreSQL 数据目录和备份目录) pg_rman init -B /backup/pg_rman -D /var/lib/pgsql/12/data # 全量备份(-b 1 表示 level 1,即全量) pg_rman backup -B /backup/pg_rman -D /var/lib/pgsql/12/data -b 1 -Z # -Z 表示压缩,节省空间

验证备份:

pg_rman show -B /backup/pg_rman # 输出应类似: # START_TIME MODE SIZE WAL_TOTAL WAL_USED DELTA STATUS # 2023-01-01 10:00:00 FULL 1.2GB 120 120 1.2GB OK

若STATUS为DELETED,说明备份被自动清理(受retention_days控制),需调大pg_rman.ini中retention_days = 30。

5.3 增量备份与归档日志的协同

pg_rman 的增量备份(level 2)依赖归档日志的连续性。必须确保:

  • archive_command正确归档所有 WAL;
  • pg_rman备份期间,主库不执行pg_archivecleanup等清理操作;
  • 备份目录/backup/pg_rman与归档目录/backup/pg_archive物理分离。

增量备份命令:

# 在全量备份后执行 pg_rman backup -B /backup/pg_rman -D /var/lib/pgsql/12/data -b 2 -Z

此时pg_rman show会显示DELTA列为增量大小,WAL_USED为本次备份覆盖的 WAL 数量。恢复时,pg_rman 会自动合并全量备份 + 增量备份 + 对应 WAL。

5.4 PITR 时间点恢复:精确到毫秒的后悔药

这是 pg_rman 的核心价值。假设误删表发生在2023-01-01 14:23:45.123,需恢复到前一秒:

# 1. 停止 PostgreSQL(备库或新实例) sudo systemctl stop postgresql-12 # 2. 清空数据目录(重要!) rm -rf /var/lib/pgsql/12/data/* # 3. 执行恢复(-r 指定恢复目标时间) pg_rman restore -B /backup/pg_rman -D /var/lib/pgsql/12/data -r "2023-01-01 14:23:44.999" # 4. 启动 PostgreSQL sudo systemctl start postgresql-12

-r参数支持完整时间格式,包括毫秒。若写成2023-01-01 14:23:44,则恢复到该秒的第一笔事务,可能多恢复一笔误操作。

血泪经验:恢复前务必确认recovery_target_timeline = 'latest'在postgresql.conf中,否则可能恢复到旧时间线,数据不完整。

5.5 备份脚本的生产级加固

附件中的pg_rman_full.sh不是简单封装,而是生产环境必需的加固:

#!/bin/bash # pg_rman_full.sh BACKUP_DIR="/backup/pg_rman" PG_DATA="/var/lib/pgsql/12/data" DATE=$(date +%Y%m%d_%H%M%S) # 1. 磁盘空间检查(预留 20%) FREE_SPACE=$(df "$BACKUP_DIR" | awk 'NR==2 {print $5}' | sed 's/%//') if [ "$FREE_SPACE" -gt 80 ]; then logger "CRITICAL: Backup disk usage > 80%" exit 1 fi # 2. 锁定备份(防并发) exec 200>"$BACKUP_DIR/backup.lock" flock -n 200 || { logger "Backup locked by another process"; exit 1; } # 3. 执行备份 pg_rman backup -B "$BACKUP_DIR" -D "$PG_DATA" -b 1 -Z --progress # 4. 校验备份完整性 if pg_rman validate -B "$BACKUP_DIR"; then logger "Backup $DATE completed and validated" else logger "Backup $DATE validation failed" exit 1 fi

关键加固点:

  • 磁盘空间预检,避免备份中途因空间不足失败;
  • flock文件锁,防止 crontab 备份重叠;
  • validate校验,确保备份集可恢复。

6. 方案验收与答辩:用三张表、两次故障模拟、一个必问问题拿下答辩

验收不是“所有服务都 running”,而是用可量化、可演示、可复现的方式证明高可用能力。我带过的每个项目,都用这三张表、两次故障模拟、一个必问问题来收尾。它们不是形式主义,而是把抽象的“高

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询