Skip to content

PostgreSQL 主从切换机制

主从切换(Failover)是 PostgreSQL 高可用架构中的核心机制,直接决定了主库故障时服务恢复的速度和数据一致性。无论是手动触发的计划性维护,还是自动化工具执行的故障恢复,掌握主从切换的原理和最佳实践对 DBA 至关重要。

主从切换概述

什么是主从切换

主从切换是指在 PostgreSQL 主从复制架构中,将一个从库提升为新主库,并重新配置其他从库连接到新主库的完整过程。这一过程确保了数据库服务在主库故障或维护时的连续性。

主从切换的类型

  • 手动切换:DBA 手动执行的切换操作,适用于计划性维护(如版本升级、硬件更换)
  • 自动切换:由自动化工具(如 Patroni、repmgr、pg_auto_failover)自动检测故障并执行
  • 受控切换:特殊的手动切换,确保主从数据完全一致,用于对数据一致性要求极高的场景

主从切换的核心目标

  • 最小化停机时间:减少业务中断时间
  • 确保数据一致性:避免数据丢失或分裂
  • 维持服务可用性:保证应用程序持续访问
  • 简化操作流程:降低切换复杂度和出错风险

手动主从切换

手动主从切换适用于计划性维护场景,DBA 可以完全控制切换过程,确保数据一致性。

生产环境准备工作

  1. 检查复制拓扑状态

    sql
    -- 主库检查所有从库状态
    SELECT application_name, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, sync_state
    FROM pg_stat_replication;
    
    -- 从库检查自身状态
    SELECT pg_is_in_recovery(), 
           pg_last_wal_receive_lsn(), 
           pg_last_wal_replay_lsn(),
           now() - pg_last_xact_replay_timestamp() AS replication_lag;
  2. 业务流量切换准备

    • 通知业务团队维护窗口
    • 切换负载均衡器至只读模式(如适用)
    • 停止主库写入操作
  3. 确保数据一致性

    sql
    -- 主库设置为只读,防止新写入
    ALTER SYSTEM SET default_transaction_read_only = on;
    SELECT pg_reload_conf();
    
    -- 等待所有从库追上主库(PostgreSQL 14+)
    SELECT pg_wal_replay_wait_lsn(pg_current_wal_lsn());
    
    -- PostgreSQL 13及以下,手动检查从库LSN
    -- 在主库执行:SELECT pg_current_wal_lsn();
    -- 在从库执行:SELECT pg_last_wal_replay_lsn();
    -- 确保两者值相等

执行手动切换步骤

方法一:使用 pg_ctl promote

bash
# 在选定的从库上执行提升命令
pg_ctl promote -D /var/lib/pgsql/16/data

# 验证提升结果
psql -U postgres -c "SELECT pg_is_in_recovery(), pg_current_wal_lsn();"

方法二:使用 SQL 命令(PostgreSQL 12+)

sql
-- 在从库执行,等待60秒确保提升完成
SELECT pg_promote(wait_seconds => 60, write_promote_file => true);

方法三:手动创建 promote 文件(PostgreSQL 10-11)

bash
# PostgreSQL 10-11 使用 recovery.conf,需创建 promote 文件
touch /var/lib/pgsql/11/data/recovery.done/promote

集群重配置与验证

  1. 更新其他从库指向新主库

    bash
    # PostgreSQL 12+ 使用 postgresql.auto.conf
    vi /var/lib/pgsql/16/data/postgresql.auto.conf
    # 修改 primary_conninfo 指向新主库
    primary_conninfo = 'host=new-master.example.com port=5432 user=replicator password=rep-pass application_name=replica2'
    
    # 重启从库或重新加载配置
    pg_ctl restart -D /var/lib/pgsql/16/data
    
    # PostgreSQL 10-11 修改 recovery.conf
    vi /var/lib/pgsql/11/data/recovery.conf
    # 修改 primary_conninfo 后重启
  2. 验证新集群状态

    sql
    -- 新主库检查从库连接
    SELECT application_name, state, sync_state FROM pg_stat_replication;
    
    -- 所有从库验证连接状态
    SELECT pg_is_in_recovery(), pg_last_wal_replay_lsn();
  3. 恢复业务流量

    • 更新负载均衡器指向新主库
    • 恢复主库读写模式
    sql
    ALTER SYSTEM RESET default_transaction_read_only;
    SELECT pg_reload_conf();

手动切换的优缺点

优点缺点
完全可控,确保数据一致性需人工干预,响应时间长
适合计划性维护依赖DBA经验,操作复杂
可提前准备,风险低不适合突发故障场景

自动主从切换

自动主从切换由高可用工具自动执行,适用于主库突发故障场景,可快速恢复服务。

自动切换工作原理

  1. 故障检测:工具通过心跳、连接或状态检查监控主库健康
  2. 故障确认:通过多节点确认或延迟检测避免误判
  3. 从库选择:根据预定义策略选择最优从库
  4. 提升操作:将选定从库提升为主库
  5. 集群重配置:更新其他从库连接
  6. 客户端重定向:更新负载均衡或DNS

主流自动化工具对比

工具故障检测从库选择策略切换速度复杂性生产适用性PostgreSQL 16支持
Patroni基于DCS心跳优先级+延迟+健康状态秒级
repmgr直接连接检查优先级+延迟秒级到分钟级
pg_auto_failover专用Monitor监控延迟+健康状态秒级
Stolon基于DCS自定义策略秒级

生产环境工具选择建议

  • 大规模集群:优先选择 Patroni,支持复杂拓扑和自定义策略
  • 中小规模集群:repmgr 或 pg_auto_failover,配置简单易维护
  • 云原生环境:Patroni 或 Stolon,与Kubernetes集成良好

自动切换的优缺点

优点缺点
响应迅速(秒级)存在误判风险
无需人工干预配置复杂,依赖外部组件
适合突发故障网络分区下可能导致脑裂
降低DBA夜间运维负担数据一致性依赖复制配置

主从切换过程详解

故障检测机制

检测方法

  • 心跳检测:定期发送心跳包,超时未响应判定为故障
  • 连接检测:尝试建立数据库连接,失败次数达到阈值触发切换
  • 状态检测:监控主库进程状态、磁盘空间等指标
  • 复制延迟检测:持续复制延迟超过阈值判定主库异常

生产环境检测策略

  • 多维度检测:结合多种检测方法,避免单一指标误判
  • 延迟确认:设置合理的检测间隔(如5秒)和重试次数(如3次)
  • 分区感知:使用多数派决策(如Patroni的DCS仲裁)防止脑裂
  • 告警前置:复制延迟达到切换阈值前提前告警,预留处理时间

从库选择策略

核心选择标准

  • 复制延迟:优先选择延迟最小的从库
  • 健康状态:排除CPU/内存/磁盘异常的从库
  • 硬件配置:选择与原主库配置相当的从库
  • 优先级设置:人工预设从库优先级
  • 地理位置:跨区域部署时选择同一区域内的从库

生产环境最佳实践

  • 明确优先级:为每个从库设置明确的优先级,避免随机选择
  • 考虑硬件差异:确保新主库能承载业务流量
  • 地理位置优化:跨区域部署时,优先选择业务流量所在区域的从库
  • 避免单点依赖:不要让所有从库依赖同一网络或存储设备

从库提升过程

  1. 停止复制进程:终止WAL接收和重放线程
  2. 触发提升:创建promote文件或执行pg_promote()
  3. 完成恢复:应用所有已接收的WAL日志
  4. 切换模式:修改内部状态为可写模式
  5. 更新系统目录:标记新主库身份,清理复制相关设置
  6. 启动复制服务:开始接受其他从库的复制连接

集群重配置

  1. 更新从库连接:修改所有从库的primary_conninfo指向新主库
  2. 重启复制:重新建立从库到新主库的复制连接
  3. 验证拓扑:确认所有从库正常连接到新主库
  4. 客户端切换:更新负载均衡器或DNS配置
  5. 监控恢复:观察新主库性能和从库复制状态

主从切换的最佳实践

1. 预先规划与配置

  • 制定详细切换计划:包含步骤、角色、责任人和回滚方案
  • 定义切换触发条件:明确手动/自动切换的触发场景和阈值
  • 配置合理的复制参数
    sql
    -- 生产环境推荐配置
    synchronous_standby_names = 'ANY 1 (replica1, replica2)'  -- 半同步复制
    wal_keep_size = '16GB'  -- 保留足够WAL日志
    max_wal_senders = 10  -- 根据从库数量调整
    hot_standby = on  -- 从库只读

2. 监控与告警

  • 核心监控指标

    • 主从复制延迟(replication lag)
    • 主库状态(pg_is_in_recovery)
    • WAL日志生成速率
    • 从库连接状态
    • 复制槽使用情况
  • 告警阈值设置

    • 复制延迟 > 30秒(普通业务)
    • 复制延迟 > 5秒(核心业务)
    • 主库不可连接 > 10秒
    • 从库状态异常 > 5秒

3. 定期测试与演练

  • 测试频率:至少每季度一次完整切换演练

  • 测试场景

    • 主库进程崩溃(kill -9 postgres)
    • 主库网络隔离(iptables屏蔽)
    • 主库磁盘满(dd填充磁盘)
    • 从库延迟切换
  • 演练文档化:记录每次演练的步骤、结果和改进点

4. 数据一致性保障

  • 根据业务选择复制类型

    • 核心业务:同步复制(synchronous_commit = on)
    • 普通业务:半同步复制(synchronous_commit = remote_write)
    • 非关键业务:异步复制(synchronous_commit = off)
  • WAL日志管理

    • 配置 wal_keep_size 或使用复制槽
    • 结合 pg_receivewal 额外备份WAL
    • 定期验证WAL完整性

5. 自动化工具优化

  • Patroni配置示例

    yaml
    scope: postgres-cluster
    name: pg1
    restart_strategy: failover
    ttl: 30
    retry_timeout: 10
    maximum_lag_on_failover: 1048576  # 1MB延迟阈值
  • repmgr配置示例

    ini
    failover=automatic
    promote_command='repmgr standby promote -f /etc/repmgr.conf --log-to-file'
    follow_command='repmgr standby follow -f /etc/repmgr.conf --log-to-file %n %d'

主从切换的常见问题与解决方案

1. 复制延迟导致的数据丢失

问题:主库故障时,从库存在较大复制延迟,切换后丢失最新数据

解决方案

  • 配置半同步或同步复制,确保关键数据已复制到从库
  • 增大 wal_keep_size 参数(PostgreSQL 13+)或使用复制槽
  • 部署 pg_receivewal 独立备份WAL日志
  • 考虑使用 pg_rewind 工具快速同步旧主库(适用于自动切换工具)

2. 脑裂问题

问题:网络分区导致多个节点同时认为自己是主库,造成数据分裂

解决方案

  • 使用奇数节点集群,实现多数派决策
  • 配置 synchronous_standby_names 要求写入确认
  • 部署fencing机制(如STONITH、IPMI断电)
  • 利用DCS(etcd/consul/zookeeper)实现分布式锁
  • PostgreSQL 15+:使用 primary_conninfoapplication_name 确保唯一主库

3. 切换后应用连接失败

问题:切换完成后,应用程序无法连接到新主库

解决方案

  • 使用支持自动发现的连接池(如PgBouncer+Patroni)
  • 配置DNS自动更新(如结合etcdctl更新DNS记录)
  • 应用程序实现连接重试和拓扑感知
  • 确保新主库 pg_hba.conf 允许应用连接
  • 检查新主库端口和防火墙配置

4. 从库提升失败

问题:执行提升操作时,从库无法成功转换为主库

解决方案

  • 检查从库状态:pg_is_in_recovery() 应为 t
  • 确认WAL日志完整性:检查 pg_wal 目录和日志文件
  • 查看从库日志:tail -n 100 /var/lib/pgsql/16/data/log/postgresql-*.log
  • 验证recovery配置:确保没有冲突的recovery参数
  • 极端情况下,考虑使用 pg_resetwal 工具(需谨慎,可能导致数据丢失)

5. 切换后性能下降

问题:切换到新主库后,数据库性能明显下降

解决方案

  • 确保新主库硬件配置与旧主库相当
  • 验证新主库参数配置与旧主库一致
  • 检查新主库的索引状态:VACUUM ANALYZE 优化
  • 分析性能瓶颈:使用 pg_stat_statementspg_stat_activity
  • 检查存储IO:使用 iostat 确认磁盘性能

PostgreSQL 10-16 版本切换机制差异

版本核心变化切换相关特性
PostgreSQL 10引入逻辑复制使用 recovery.conf,需手动创建promote文件
无内置 pg_promote() 函数
复制槽增强
PostgreSQL 11增强并行查询保留 recovery.conf 机制
改进复制槽管理
支持 pg_wal_replay_pause()/resume()
PostgreSQL 12移除 recovery.conf引入 pg_promote() 函数
复制配置移至 postgresql.auto.conf
支持 recovery.signalstandby.signal 文件
PostgreSQL 13增强WAL管理引入 wal_keep_size 参数
改进 pg_stat_replication 视图
支持 pg_rewind 自动清理
PostgreSQL 14增强高可用引入 pg_wal_replay_wait_lsn() 函数
改进同步复制行为
增强复制监控指标
PostgreSQL 15安全与性能增强改进 pg_stat_replication 视图,增加更多指标
增强复制槽可靠性
改进WAL发送机制
PostgreSQL 16并行与监控增强改进复制性能
增强 pg_stat_replication 中的延迟指标
支持更多自动切换工具集成

版本迁移注意事项

  • 从 PostgreSQL 10-11 升级到 12+

    • 移除 recovery.conf,改用 postgresql.auto.conf 和 signal 文件
    • 开始使用 pg_promote() 函数替代手动创建promote文件
  • 从 PostgreSQL 12-13 升级到 14+

    • 使用 pg_wal_replay_wait_lsn() 简化复制等待
    • 利用增强的监控视图改进切换决策
  • PostgreSQL 16 新特性

    • 更精确的复制延迟监控
    • 改进的WAL发送机制,减少切换时间
    • 更好的自动切换工具集成支持