Skip to content

PostgreSQL 复制失败处理

复制失败的定义

复制失败是指PostgreSQL主从复制系统中,从库无法正常接收、应用或同步主库的WAL日志,导致主从数据不一致或复制关系中断的情况。

复制失败的影响

  1. 数据不一致:主从库数据出现差异,影响数据可靠性
  2. 高可用失效:无法进行故障切换,影响系统可用性
  3. 读写分离不可用:应用无法使用从库进行读操作,增加主库负载
  4. 恢复能力下降:失去从库备份,增加数据丢失风险
  5. 业务中断风险:主库故障时无法快速恢复服务

复制失败的常见类型

  1. 连接失败:主从库之间网络连接中断
  2. 同步失败:从库无法接收或应用WAL日志
  3. 延迟超限:复制延迟超过设定阈值
  4. 复制槽故障:复制槽异常导致WAL日志丢失
  5. 配置错误:复制配置参数错误
  6. 版本不兼容:主从库PostgreSQL版本差异过大

复制失败的原因分析

网络问题

  1. 网络中断

    • 物理网络故障
    • 防火墙配置错误
    • 网络带宽不足
    • 网络延迟过高
  2. 连接配置问题

    • 监听地址配置错误
    • 端口配置错误
    • 认证配置错误
    • 连接数限制

配置错误

  1. 复制参数配置错误

    • max_wal_senders 设置过小
    • wal_keep_size 设置不足
    • hot_standby 配置错误
    • primary_conninfo 配置错误
  2. 权限配置错误

    • 复制用户权限不足
    • pg_hba.conf 配置错误
    • 认证方法配置错误
  3. WAL配置错误

    • wal_level 配置过低
    • archive_mode 配置错误
    • archive_command 配置错误

资源不足

  1. 磁盘空间不足

    • 主库WAL日志堆积
    • 从库数据目录满
    • 归档目录空间不足
  2. 内存不足

    • 从库 shared_buffers 不足
    • 从库 work_mem 不足
    • 系统内存不足导致OOM
  3. CPU资源不足

    • 从库CPU使用率过高
    • 主库WAL生成速率超过从库处理能力
    • 并行查询消耗过多CPU资源

数据不一致

  1. WAL日志损坏

    • 主库WAL日志文件损坏
    • 归档WAL日志损坏
    • 网络传输中WAL日志损坏
  2. 从库数据损坏

    • 从库数据文件损坏
    • 从库索引损坏
    • 从库系统表损坏
  3. 初始同步不完整

    • 基础备份不完整
    • 基础备份与WAL日志不匹配
    • 初始同步过程中断

软件问题

  1. 版本不兼容

    • 主从库PostgreSQL版本差异过大
    • 扩展版本不兼容
    • 操作系统版本差异
  2. 软件bug

    • PostgreSQL内核bug
    • 复制相关功能bug
    • 第三方扩展bug
  3. 配置变更

    • 主库参数变更未同步到从库
    • 从库配置文件修改错误
    • 硬件配置变更

复制失败的诊断方法

查看复制状态

  1. 主库复制状态查询

    sql
    -- 查看发送者进程状态
    SELECT * FROM pg_stat_replication;
    
    -- 查看复制槽状态
    SELECT * FROM pg_replication_slots;
    
    -- 查看WAL发送统计
    SELECT * FROM pg_stat_wal;
    
    -- 查看连接数
    SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'walsender';
  2. 从库复制状态查询

    sql
    -- 查看WAL接收器状态
    SELECT * FROM pg_stat_wal_receiver;
    
    -- 查看从库同步状态
    SELECT * FROM pg_stat_replication;
    
    -- 查看复制延迟
    SELECT now() - pg_last_xact_replay_timestamp() AS replication_delay;
    
    -- 查看恢复状态
    SELECT * FROM pg_stat_wal_receiver;
  3. 系统级复制状态检查

    bash
    # 检查主库WAL发送进程
    ps aux | grep wal sender process
    
    # 检查从库WAL接收进程
    ps aux | grep wal receiver process
    
    # 检查从库恢复进程
    ps aux | grep startup process

分析日志文件

  1. 主库日志分析

    bash
    # 查看主库日志中的复制相关信息
    grep -i "wal sender\|replication" /var/log/postgresql/postgresql-14-main.log
    
    # 查看错误信息
    grep -i "error\|warning\|fatal" /var/log/postgresql/postgresql-14-main.log
  2. 从库日志分析

    bash
    # 查看从库日志中的复制相关信息
    grep -i "wal receiver\|recovery\|standby" /var/log/postgresql/postgresql-14-main.log
    
    # 查看恢复过程日志
    grep -i "restore\|apply\|recover" /var/log/postgresql/postgresql-14-main.log
  3. 系统日志分析

    bash
    # 查看系统日志中的网络相关信息
    grep -i "network\|interface\|firewall" /var/log/syslog
    
    # 查看磁盘空间相关信息
    grep -i "disk\|space\|full" /var/log/syslog

检查系统资源

  1. 磁盘空间检查

    bash
    # 检查主库磁盘空间
    df -h /var/lib/postgresql/14/main
    
    # 检查从库磁盘空间
    df -h /var/lib/postgresql/14/standby
    
    # 检查WAL归档目录空间
    df -h /path/to/wal/archive
  2. 内存使用检查

    bash
    # 查看内存使用情况
    free -h
    
    # 查看PostgreSQL进程内存使用
    ps aux --sort=-%mem | grep postgres
  3. CPU使用检查

    bash
    # 查看CPU使用率
    top
    
    # 查看PostgreSQL进程CPU使用
    ps aux --sort=-%cpu | grep postgres
  4. 网络连接检查

    bash
    # 测试主从库之间的网络连接
    ping -c 5 主库IP
    
    # 测试PostgreSQL端口连通性
    telnet 主库IP 5432
    
    # 使用psql测试连接
    psql -h 主库IP -U replication -d postgres

验证配置

  1. 主库配置检查

    sql
    -- 检查复制相关参数
    SHOW wal_level;
    SHOW max_wal_senders;
    SHOW wal_keep_size;
    SHOW archive_mode;
    SHOW archive_command;
  2. 从库配置检查

    sql
    -- 检查恢复相关参数
    SHOW hot_standby;
    SHOW max_standby_streaming_delay;
    SHOW wal_receiver_status_interval;
    
    -- 检查primary_conninfo配置
    SELECT setting FROM pg_settings WHERE name = 'primary_conninfo';
  3. 配置文件检查

    bash
    # 检查主库pg_hba.conf
    grep -i replication /etc/postgresql/14/main/pg_hba.conf
    
    # 检查从库recovery.conf或postgresql.auto.conf
    grep -i primary_conninfo /var/lib/postgresql/14/standby/postgresql.auto.conf

复制失败的恢复步骤

简单复制失败的恢复

  1. 重启WAL接收器

    bash
    # 从库重启PostgreSQL服务
    systemctl restart postgresql
  2. 重新建立复制连接

    sql
    -- 从库中重新启动恢复进程
    SELECT pg_reload_conf();
  3. 调整复制参数

    sql
    -- 主库增加max_wal_senders
    ALTER SYSTEM SET max_wal_senders = 10;
    SELECT pg_reload_conf();
    
    -- 主库增加wal_keep_size
    ALTER SYSTEM SET wal_keep_size = '1GB';
    SELECT pg_reload_conf();

中等复制失败的恢复

  1. 重建复制槽

    sql
    -- 主库删除失效的复制槽
    SELECT pg_drop_replication_slot('slot_name');
    
    -- 主库重新创建复制槽
    SELECT pg_create_physical_replication_slot('slot_name');
  2. 修复WAL归档问题

    bash
    # 检查归档命令
    tail -n 10 /var/log/postgresql/postgresql-14-main.log | grep archive
    
    # 修复归档目录权限
    chown -R postgres:postgres /path/to/wal/archive
    chmod 700 /path/to/wal/archive
  3. 清理旧WAL日志

    sql
    -- 主库手动清理WAL日志(谨慎使用)
    SELECT pg_switch_wal();
    
    -- 检查WAL日志保留情况
    SELECT pg_walfile_name(pg_current_wal_lsn());

复杂复制失败的恢复

  1. 从库重建(基于pg_basebackup)

    bash
    # 停止从库服务
    systemctl stop postgresql
    
    # 清空从库数据目录
    rm -rf /var/lib/postgresql/14/standby/*
    
    # 使用pg_basebackup重新同步
    pg_basebackup -h 主库IP -p 5432 -U replication -D /var/lib/postgresql/14/standby -Fp -Xs -P -R
    
    # 启动从库服务
    systemctl start postgresql
  2. 从库重建(基于归档恢复)

    bash
    # 停止从库服务
    systemctl stop postgresql
    
    # 清空从库数据目录
    rm -rf /var/lib/postgresql/14/standby/*
    
    # 恢复基础备份
    tar -xzf /path/to/base/backup.tar.gz -C /var/lib/postgresql/14/standby
    
    # 配置recovery.signal
    echo "standby_mode = 'on'" > /var/lib/postgresql/14/standby/recovery.signal
    echo "primary_conninfo = 'host=主库IP port=5432 user=replication password=密码'" >> /var/lib/postgresql/14/standby/recovery.signal
    echo "restore_command = 'cp /path/to/wal/archive/%f %p'" >> /var/lib/postgresql/14/standby/recovery.signal
    
    # 启动从库服务
    systemctl start postgresql
  3. 主库故障切换

    bash
    # 在从库上执行故障切换
    pg_ctl promote -D /var/lib/postgresql/14/standby
    
    # 或使用SQL命令
    SELECT pg_promote();
  4. 修复数据不一致

    sql
    -- 检查主从数据一致性
    SELECT * FROM dblink('host=主库IP user=postgres dbname=dbname', 'SELECT id FROM table_name ORDER BY id') AS t(id int)
    EXCEPT
    SELECT id FROM table_name ORDER BY id;
    
    -- 修复数据不一致(谨慎使用)
    -- 注意:此操作可能导致数据丢失,建议在专业人员指导下进行

不同类型复制的故障处理

流复制故障处理

  1. 流复制故障特征

    • 从库 pg_stat_wal_receiver 状态异常
    • 主库 pg_stat_replication 中对应从库消失
    • 复制延迟持续增加
  2. 流复制故障恢复步骤

    • 检查网络连接
    • 检查主库 max_wal_senders 设置
    • 检查 wal_keep_size 或复制槽配置
    • 重启从库WAL接收器
    • 必要时重建从库

逻辑复制故障处理

  1. 逻辑复制故障特征

    • 发布者或订阅者日志中出现错误
    • 订阅状态显示为 down
    • 复制进度停滞
  2. 逻辑复制故障恢复步骤

    sql
    -- 检查逻辑复制状态
    SELECT * FROM pg_stat_subscription;
    SELECT * FROM pg_stat_publication;
    
    -- 重启逻辑复制
    ALTER SUBSCRIPTION subscription_name REFRESH PUBLICATION;
    
    -- 重新创建逻辑复制
    DROP SUBSCRIPTION IF EXISTS subscription_name;
    CREATE SUBSCRIPTION subscription_name CONNECTION 'host=主库IP port=5432 user=replication dbname=dbname' PUBLICATION publication_name;
  3. 逻辑复制冲突处理

    sql
    -- 查看冲突信息
    SELECT * FROM pg_stat_database_conflicts;
    
    -- 处理冲突(根据实际情况选择)
    -- 1. 跳过冲突事务
    ALTER SUBSCRIPTION subscription_name SET (skip_errors = true);
    
    -- 2. 手动解决冲突后重启复制
    -- 3. 重新初始化订阅

物理复制故障处理

  1. 物理复制故障特征

    • 从库无法启动
    • 从库日志中出现数据损坏错误
    • 主从库WAL日志不匹配
  2. 物理复制故障恢复步骤

    • 检查从库数据文件完整性
    • 验证基础备份的完整性
    • 重建从库
    • 确保主从库版本兼容
    • 检查硬件故障

复制失败的预防措施

监控复制状态

  1. 设置监控告警

    • 复制延迟超过阈值告警
    • 复制连接中断告警
    • 从库状态异常告警
    • WAL日志堆积告警
  2. 使用监控工具

    • Prometheus + Grafana
    • Zabbix
    • Nagios
    • pgMonitor
  3. 自定义监控脚本

    bash
    # 检查复制延迟的脚本示例
    REPLICATION_DELAY=$(psql -h 从库IP -U postgres -t -c "SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::int")
    
    if [ $REPLICATION_DELAY -gt 300 ]; then
        echo "复制延迟超过5分钟,当前延迟:${REPLICATION_DELAY}秒"
        # 发送告警
    fi

定期测试复制

  1. 定期进行故障切换测试

    • 每季度至少进行一次手动故障切换
    • 记录切换时间和过程
    • 测试回切流程
  2. 定期验证数据一致性

    • 使用 pg_verifybackup 验证备份完整性
    • 定期比较主从库关键表数据
    • 使用第三方工具如 pgAdmin 进行数据一致性检查
  3. 测试恢复流程

    • 定期从备份恢复从库
    • 测试不同场景下的恢复时间
    • 验证恢复后的数据完整性

合理配置复制参数

  1. 主库复制参数优化

    sql
    -- 合理设置WAL保留
    ALTER SYSTEM SET wal_keep_size = '2GB';
    
    -- 增加WAL发送进程数
    ALTER SYSTEM SET max_wal_senders = 10;
    
    -- 启用复制槽
    -- 注意:使用复制槽时需确保从库正常运行,避免WAL日志堆积
  2. 从库复制参数优化

    sql
    -- 设置合理的流复制延迟
    ALTER SYSTEM SET max_standby_streaming_delay = '30s';
    
    -- 设置WAL接收器状态报告间隔
    ALTER SYSTEM SET wal_receiver_status_interval = '10s';
    
    -- 启用热备
    ALTER SYSTEM SET hot_standby = on;
  3. 网络参数优化

    • 调整TCP连接超时参数
    • 优化网络缓冲区大小
    • 使用专用网络进行复制

保持软件版本一致

  1. 主从库版本匹配

    • 确保主从库PostgreSQL版本一致
    • 版本差异不超过一个主版本
    • 及时更新补丁版本
  2. 扩展版本兼容

    • 确保主从库扩展版本一致
    • 升级扩展时同步更新主从库
    • 测试扩展兼容性
  3. 操作系统版本兼容

    • 主从库操作系统版本尽量一致
    • 确保系统库版本兼容
    • 测试跨平台复制兼容性

实施高可用架构

  1. 使用Patroni或repmgr

    • 自动故障检测和切换
    • 自动恢复复制关系
    • 集中管理复制配置
  2. 实施多从库架构

    • 部署多个从库,分散风险
    • 不同从库使用不同的复制方式
    • 跨可用区部署从库
  3. 使用负载均衡

    • 配置PgBouncer或Pgpool-II
    • 自动检测从库状态
    • 自动剔除故障从库

复制失败的监控与告警

关键监控指标

  1. 复制状态指标

    • 复制延迟时间
    • 复制连接状态
    • WAL发送速率
    • WAL应用速率
    • 复制槽状态
  2. 系统资源指标

    • 磁盘使用率
    • 内存使用率
    • CPU使用率
    • 网络带宽使用率
    • 网络延迟
  3. PostgreSQL指标

    • 连接数
    • WAL日志生成速率
    • 锁等待情况
    • 慢查询数量
    • 缓冲区命中率

告警配置建议

告警项告警阈值告警级别处理建议
复制延迟> 300秒警告检查网络和系统资源
复制延迟> 600秒严重立即检查复制状态,必要时重建从库
复制连接中断连接数=0严重检查网络连接和主库状态
从库磁盘使用率> 90%警告清理磁盘空间或扩容
从库磁盘使用率> 95%严重立即清理磁盘空间
主库WAL堆积> 100GB警告检查从库状态和复制槽配置
复制槽溢出wal_keep_size不足严重增加wal_keep_size或修复从库

常见问题与解决方案

Q1: 从库无法连接到主库怎么办?

A1: 从库无法连接到主库的解决步骤:

  1. 检查网络连接

    bash
    ping 主库IP
    telnet 主库IP 5432
  2. 检查主库监听配置

    sql
    SHOW listen_addresses;
    SHOW port;
  3. 检查pg_hba.conf配置

    bash
    grep -i replication /etc/postgresql/14/main/pg_hba.conf
  4. 检查复制用户权限

    sql
    SELECT usename, usesuper, replication FROM pg_user WHERE usename = 'replication';
  5. 检查主库max_wal_senders设置

    sql
    SHOW max_wal_senders;
    SELECT count(*) FROM pg_stat_replication;

Q2: 复制延迟持续增加怎么办?

A2: 复制延迟持续增加的解决步骤:

  1. 检查从库系统资源

    bash
    top
    df -h
    free -h
  2. 检查主库WAL生成速率

    sql
    SELECT * FROM pg_stat_wal;
  3. 检查从库WAL应用速率

    sql
    SELECT * FROM pg_stat_bgwriter;
  4. 调整复制参数

    sql
    -- 主库增加wal_keep_size
    ALTER SYSTEM SET wal_keep_size = '2GB';
    
    -- 从库调整max_standby_streaming_delay
    ALTER SYSTEM SET max_standby_streaming_delay = '60s';
  5. 考虑升级硬件

    • 增加从库CPU核心数
    • 提高从库内存
    • 使用更快的存储设备
    • 优化网络带宽

Q3: 复制槽导致主库WAL日志堆积怎么办?

A3: 复制槽导致WAL日志堆积的解决步骤:

  1. 检查复制槽状态

    sql
    SELECT * FROM pg_replication_slots;
  2. 检查WAL日志使用情况

    bash
    du -sh /var/lib/postgresql/14/main/pg_wal/*
  3. 修复或删除失效的复制槽

    sql
    -- 修复从库连接
    -- 或删除失效的复制槽
    SELECT pg_drop_replication_slot('slot_name');
  4. 调整复制槽配置

    sql
    -- 使用临时复制槽
    CREATE_REPLICATION_SLOT slot_name TEMPORARY;

Q4: 从库重建后仍然无法同步怎么办?

A4: 从库重建后无法同步的解决步骤:

  1. 检查基础备份完整性

    bash
    # 验证基础备份
    pg_verifybackup /path/to/base/backup
  2. 检查WAL日志完整性

    bash
    # 验证WAL日志
    pg_waldump /path/to/wal/archive/000000010000000000000001
  3. 检查主从库版本兼容性

    bash
    # 检查主库版本
    psql -h 主库IP -U postgres -c "SELECT version();"
    
    # 检查从库版本
    psql -h 从库IP -U postgres -c "SELECT version();"
  4. 检查恢复配置

    bash
    cat /var/lib/postgresql/14/standby/postgresql.auto.conf
  5. 查看详细日志

    bash
    tail -n 100 /var/log/postgresql/postgresql-14-main.log

常见问题(FAQ)

Q1: 复制失败会导致数据丢失吗?

A1: 复制失败是否导致数据丢失取决于复制配置:

  • 异步复制:可能导致数据丢失,因为主库提交事务后立即返回,不等待从库确认
  • 同步复制:主库提交事务后等待从库确认,不会导致数据丢失,但会影响性能
  • 半同步复制:主库提交事务后等待至少一个从库确认,平衡了性能和数据安全性

建议根据业务需求选择合适的复制模式,并配置适当的复制槽或WAL保留策略。

Q2: 如何区分是主库问题还是从库问题?

A2: 区分主库和从库问题的方法:

  • 检查多个从库:如果所有从库都出现问题,可能是主库问题
  • 检查主库日志:主库日志中是否有错误信息
  • 检查从库日志:从库日志中是否有连接或应用错误
  • 测试主库连接:使用psql测试能否连接到主库
  • 检查主库资源:主库是否有资源瓶颈

Q3: 复制失败后如何验证数据一致性?

A3: 验证数据一致性的方法:

  1. 使用pg_syncdiff工具

    • 专门用于比较PostgreSQL主从库数据一致性
    • 支持表级和行级比较
    • 生成差异报告
  2. 使用check_postgres插件

    • 提供复制一致性检查功能
    • 可以集成到监控系统
    • 支持自动告警
  3. 手动验证关键表

    sql
    -- 比较表行数
    SELECT COUNT(*) FROM table_name;
    
    -- 比较表哈希值
    SELECT md5(CAST((array_agg(t.* ORDER BY id)) AS text)) FROM table_name t;

Q4: 如何预防复制失败?

A4: 预防复制失败的措施:

  1. 实施完善的监控和告警
  2. 定期进行复制测试和演练
  3. 保持主从库版本一致
  4. 合理配置复制参数
  5. 使用高可用工具如Patroni
  6. 部署多个从库,分散风险
  7. 定期备份和验证
  8. 培训团队成员,提高故障处理能力

Q5: 复制失败后需要多长时间恢复?

A5: 复制失败的恢复时间取决于:

  • 故障类型:简单故障几分钟内恢复,复杂故障可能需要数小时
  • 数据量大小:数据量越大,重建从库时间越长
  • 网络带宽:网络带宽影响基础备份传输时间
  • 系统资源:CPU、内存和磁盘速度影响WAL应用速度
  • 恢复经验:团队故障处理经验影响恢复效率

建议制定详细的恢复计划,并定期进行演练,以缩短实际恢复时间。

Q6: 如何在不影响业务的情况下重建从库?

A6: 在线重建从库的方法:

  1. 使用pg_basebackup的--checkpoint选项

    bash
    pg_basebackup -h 主库IP -p 5432 -U replication -D /var/lib/postgresql/14/standby -Fp -Xs -P -R --checkpoint=fast
  2. 使用并行备份

    bash
    # 使用pg_basebackup的-j选项启用并行备份
    pg_basebackup -h 主库IP -p 5432 -U replication -D /var/lib/postgresql/14/standby -Fp -Xs -P -R -j 4
  3. 使用现有从库进行级联复制

    • 从现有从库创建新从库,减少主库负载
    • 使用级联复制配置
    • 适用于多从库架构
  4. 选择业务低峰期进行重建

    • 避免在业务高峰期重建从库
    • 提前通知相关团队
    • 准备回滚方案