Skip to content

PostgreSQL 常见故障快速恢复指南

故障分类与优先级

故障分类

  1. 紧急故障

    • 数据库服务完全不可用
    • 主从复制完全中断
    • 数据损坏
    • 磁盘空间耗尽
  2. 严重故障

    • 部分服务不可用
    • 复制延迟超过阈值
    • 大量慢查询
    • 高CPU/内存使用率
  3. 一般故障

    • 单个连接失败
    • 小范围性能下降
    • 非关键日志报错

恢复优先级

优先级故障类型恢复时间目标
P0紧急故障立即恢复
P1严重故障30分钟内恢复
P2一般故障4小时内恢复

连接问题快速恢复

症状识别

  • 应用无法连接到数据库
  • 连接超时错误
  • "connection refused" 错误
  • 连接数达到上限

恢复步骤

  1. 检查PostgreSQL服务状态

    bash
    # 检查服务状态
    systemctl status postgresql
    
    # 如果服务停止,启动服务
    systemctl start postgresql
  2. 检查监听配置

    bash
    # 检查是否监听正确的地址和端口
    netstat -tlnp | grep postgres
    
    # 或者使用ss命令
    ss -tlnp | grep postgres
  3. 检查连接数

    sql
    -- 查看当前连接数
    SELECT count(*) FROM pg_stat_activity;
    
    -- 查看最大连接数配置
    SHOW max_connections;
    
    -- 查看等待连接的进程
    SELECT * FROM pg_stat_activity WHERE state = 'waiting';
  4. 释放空闲连接

    sql
    -- 终止空闲时间超过30分钟的连接
    SELECT pg_terminate_backend(pid) 
    FROM pg_stat_activity 
    WHERE state = 'idle' 
    AND current_timestamp - state_change > interval '30 minutes';
  5. 临时调整连接数

    sql
    -- 临时增加最大连接数
    ALTER SYSTEM SET max_connections = 500;
    
    -- 重新加载配置
    SELECT pg_reload_conf();

预防措施

  • 配置合理的连接超时参数
  • 使用连接池管理连接
  • 设置空闲连接自动清理机制
  • 监控连接数变化趋势

复制失败快速恢复

症状识别

  • 复制延迟持续增加
  • 从库状态显示"down"
  • WAL日志堆积
  • 复制槽状态异常

恢复步骤

  1. 检查复制状态

    sql
    -- 主库查看复制状态
    SELECT * FROM pg_stat_replication;
    
    -- 从库查看复制状态
    SELECT * FROM pg_stat_wal_receiver;
    
    -- 查看复制槽状态
    SELECT * FROM pg_replication_slots;
  2. 重启WAL接收器

    bash
    # 从库重启PostgreSQL服务
    systemctl restart postgresql
  3. 重新初始化从库

    bash
    # 在从库上执行
    # 停止PostgreSQL服务
    systemctl stop postgresql
    
    # 清空数据目录
    rm -rf /var/lib/postgresql/14/main/*
    
    # 使用pg_basebackup重新同步
    pg_basebackup -h 主库IP -p 5432 -U replication -D /var/lib/postgresql/14/main -Fp -Xs -P -R
    
    # 启动从库服务
    systemctl start postgresql
  4. 修复复制槽问题

    sql
    -- 删除无效复制槽
    SELECT pg_drop_replication_slot('slot_name');
    
    -- 重新创建复制槽
    SELECT pg_create_physical_replication_slot('slot_name');

预防措施

  • 监控复制延迟
  • 配置适当的WAL保留策略
  • 使用复制槽确保数据不丢失
  • 定期验证复制完整性

死锁问题快速恢复

症状识别

  • 应用出现"deadlock detected"错误
  • 查询长时间处于等待状态
  • 锁等待图出现循环

恢复步骤

  1. 识别死锁

    sql
    -- 查看当前锁情况
    SELECT * FROM pg_locks WHERE NOT granted;
    
    -- 查看锁等待关系
    SELECT blocked_locks.pid AS blocked_pid,
           blocked_activity.usename AS blocked_user,
           blocking_locks.pid AS blocking_pid,
           blocking_activity.usename AS blocking_user,
           blocked_activity.query AS blocked_query,
           blocking_activity.query AS blocking_query
    FROM pg_catalog.pg_locks blocked_locks
    JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
    JOIN pg_catalog.pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype
        AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
        AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
        AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
        AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
        AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
        AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
        AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
        AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
        AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
        AND blocking_locks.pid != blocked_locks.pid
    JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
    WHERE NOT blocked_locks.granted;
  2. 终止阻塞进程

    sql
    -- 终止阻塞进程
    SELECT pg_terminate_backend(blocking_pid);
  3. 清理死锁事务

    sql
    -- 查看长时间运行的事务
    SELECT pid, usename, datname, query, state, 
           current_timestamp - xact_start AS xact_duration
    FROM pg_stat_activity
    WHERE state IN ('active', 'idle in transaction')
    ORDER BY xact_duration DESC;
    
    -- 终止长时间运行的事务
    SELECT pg_terminate_backend(pid);

预防措施

  • 保持事务简短
  • 统一锁定顺序
  • 使用适当的隔离级别
  • 设置合理的锁超时参数
  • 监控锁等待情况

磁盘空间不足快速恢复

症状识别

  • "no space left on device" 错误
  • 磁盘使用率接近100%
  • 写入操作失败
  • 日志无法滚动

恢复步骤

  1. 紧急释放空间

    bash
    # 删除旧日志文件
    find /var/log/postgresql -name "*.log.*" -type f -mtime +7 -delete
    
    # 清理pg_wal目录中的旧文件(仅当确认安全时)
    # 注意:此操作可能导致数据丢失,需谨慎
    rm -f /var/lib/postgresql/14/main/pg_wal/000000010000000000000001.00000028.backup
  2. 检查磁盘使用情况

    bash
    # 查看磁盘使用率
    df -h
    
    # 查看目录大小
    du -sh /var/lib/postgresql/*
    
    # 查找大文件
    find /var/lib/postgresql -type f -size +100M | sort -nk 5 -r
  3. 清理WAL归档

    bash
    # 清理7天前的WAL归档文件
    find /path/to/wal/archive -name "*.backup" -o -name "*.gz" -o -name "*" -type f -mtime +7 -delete
  4. 真空清理大表

    sql
    -- 查看表大小
    SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) 
    FROM pg_stat_user_tables 
    ORDER BY pg_total_relation_size(relid) DESC LIMIT 10;
    
    -- 执行真空清理
    VACUUM FULL VERBOSE ANALYZE large_table;
  5. 扩展磁盘空间

    bash
    # 扩展LVM逻辑卷(如果使用LVM)
    lvextend -L +50G /dev/vg_postgres/lv_data
    
    # 扩展文件系统
    resize2fs /dev/vg_postgres/lv_data

预防措施

  • 配置自动清理策略
  • 监控磁盘使用率趋势
  • 设置磁盘空间告警阈值
  • 定期执行真空清理
  • 合理规划存储容量

高CPU/内存使用率快速恢复

症状识别

  • CPU使用率持续超过90%
  • 内存使用率接近100%
  • 系统响应缓慢
  • 大量swap使用

恢复步骤

  1. 识别占用资源的进程

    bash
    # 查看CPU占用最高的进程
    top -c
    
    # 查看PostgreSQL进程
    ps aux | grep postgres | sort -nk 3 -r
  2. 识别消耗资源的查询

    sql
    -- 查看当前运行的查询及其资源使用情况
    SELECT pid, usename, datname, query, state, 
           pg_total_relation_size(relid) AS rel_size,
           current_timestamp - query_start AS query_duration
    FROM pg_stat_activity
    WHERE query NOT LIKE '%pg_stat_activity%'
    ORDER BY query_duration DESC LIMIT 10;
    
    -- 终止消耗资源的查询
    SELECT pg_terminate_backend(pid);
  3. 调整内存配置

    sql
    -- 临时调整shared_buffers
    ALTER SYSTEM SET shared_buffers = '2GB';
    
    -- 临时调整work_mem
    ALTER SYSTEM SET work_mem = '64MB';
    
    -- 重新加载配置
    SELECT pg_reload_conf();
  4. 优化查询

    sql
    -- 查看慢查询日志
    SELECT * FROM pg_stat_statements 
    ORDER BY total_exec_time DESC LIMIT 10;
    
    -- 分析查询计划
    EXPLAIN ANALYZE SELECT * FROM large_table WHERE column = 'value';

预防措施

  • 监控CPU/内存使用率
  • 优化查询性能
  • 配置合理的内存参数
  • 定期分析慢查询
  • 考虑垂直或水平扩展

慢查询风暴快速恢复

症状识别

  • 大量慢查询同时运行
  • 数据库响应时间急剧下降
  • 连接队列堆积
  • 锁竞争加剧

恢复步骤

  1. 启用慢查询日志

    sql
    -- 临时启用慢查询日志
    ALTER SYSTEM SET log_min_duration_statement = 500;
    SELECT pg_reload_conf();
  2. 批量终止慢查询

    sql
    -- 终止所有运行时间超过1分钟的查询
    SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE state = 'active'
    AND current_timestamp - query_start > interval '1 minute';
  3. 调整查询处理参数

    sql
    -- 临时降低max_parallel_workers
    ALTER SYSTEM SET max_parallel_workers = 2;
    
    -- 调整random_page_cost
    ALTER SYSTEM SET random_page_cost = 4;
    
    -- 重新加载配置
    SELECT pg_reload_conf();
  4. 限流措施

    bash
    # 使用pgpool-II或其他中间件进行查询限流
    # 调整连接池配置

预防措施

  • 实施查询限流
  • 配置合理的查询超时
  • 优化索引设计
  • 定期分析查询性能
  • 实施查询审核机制

数据损坏快速恢复

症状识别

  • "invalid page header" 错误
  • 表扫描失败
  • CRC校验错误
  • 数据库启动失败

恢复步骤

  1. 确认损坏范围

    sql
    -- 检查数据库完整性
    SELECT pg_relation_check('table_name');
    
    -- 或使用pg_checksums
    pg_checksums -c -D /var/lib/postgresql/14/main
  2. 从备份恢复

    bash
    # 停止PostgreSQL服务
    systemctl stop postgresql
    
    # 恢复基础备份
    tar -xzf /path/to/backup/base.tar.gz -C /var/lib/postgresql/14/main
    
    # 恢复WAL日志
    pg_waldump /path/to/wal/archive/000000010000000000000001 | pg_walrestore -D /var/lib/postgresql/14/main
    
    # 启动PostgreSQL服务
    systemctl start postgresql
  3. 修复单个表

    sql
    -- 尝试修复损坏的表
    REINDEX TABLE table_name;
    
    -- 或使用COPY重建表
    CREATE TABLE table_name_new AS SELECT * FROM table_name WHERE 1=0;
    COPY table_name_new FROM PROGRAM 'pg_dump -t table_name -a -d dbname';
  4. 使用pg_resetwal(仅作为最后手段)

    bash
    # 注意:此操作可能导致数据丢失
    pg_resetwal -f /var/lib/postgresql/14/main

预防措施

  • 启用数据校验和
  • 定期执行完整性检查
  • 实施多副本策略
  • 定期测试恢复流程
  • 使用可靠的存储设备

恢复验证与后续处理

恢复验证步骤

  1. 服务可用性验证

    bash
    # 验证服务是否正常运行
    pg_isready -h localhost -p 5432
    
    # 连接测试
    psql -U postgres -c "SELECT 1;"
  2. 数据完整性验证

    sql
    -- 检查表计数
    SELECT count(*) FROM critical_table;
    
    -- 验证关键数据
    SELECT * FROM critical_table WHERE id = 1;
  3. 性能验证

    sql
    -- 检查查询性能
    EXPLAIN ANALYZE SELECT * FROM large_table LIMIT 100;
    
    -- 检查系统负载
    SELECT * FROM pg_stat_bgwriter;
  4. 复制状态验证

    sql
    -- 验证复制是否正常
    SELECT * FROM pg_stat_replication;
    SELECT * FROM pg_stat_wal_receiver;

后续处理

  1. 故障根因分析

    • 记录故障时间、症状和恢复过程
    • 分析日志找出根本原因
    • 制定预防措施
  2. 文档更新

    • 更新故障恢复手册
    • 记录新的故障类型和恢复方法
    • 更新监控告警规则
  3. 测试与演练

    • 定期进行故障恢复演练
    • 测试新的恢复方法
    • 验证备份完整性
  4. 改进措施

    • 优化系统配置
    • 增强监控告警
    • 改进架构设计
    • 提升团队技能

常见问题(FAQ)

Q1: 如何快速识别PostgreSQL故障类型?

A1: 可以通过以下方法快速识别故障类型:

  • 查看PostgreSQL日志文件
  • 使用pg_stat_activity视图查看数据库活动
  • 检查系统资源使用情况
  • 监控告警信息
  • 测试基本连接和查询

Q2: 恢复过程中需要注意哪些事项?

A2: 恢复过程中需要注意:

  • 不要随意终止PostgreSQL进程
  • 避免在恢复过程中进行无关操作
  • 记录恢复步骤和结果
  • 确保备份文件的完整性
  • 恢复后进行验证
  • 及时通知相关人员

Q3: 如何避免类似故障再次发生?

A3: 避免故障再次发生的措施:

  • 实施完善的监控系统
  • 定期进行性能优化
  • 保持数据库更新到最新版本
  • 实施合理的备份策略
  • 定期进行故障演练
  • 培训团队成员

Q4: 什么时候需要寻求外部帮助?

A4: 以下情况建议寻求外部帮助:

  • 无法识别故障原因
  • 恢复过程中遇到技术难题
  • 数据损坏严重
  • 恢复时间超过预期
  • 涉及关键业务系统

Q5: 如何制定有效的故障恢复计划?

A5: 制定故障恢复计划的步骤:

  • 识别关键业务系统和数据
  • 分析可能的故障场景
  • 制定详细的恢复流程
  • 明确责任人和时间要求
  • 定期测试和更新计划
  • 确保所有团队成员熟悉计划

Q6: 如何平衡恢复速度和数据安全性?

A6: 平衡恢复速度和数据安全性的方法:

  • 实施分层备份策略
  • 使用增量备份和差异备份
  • 考虑使用PITR(时间点恢复)
  • 测试不同恢复方法的速度和安全性
  • 根据业务需求调整恢复策略

Q7: 如何监控恢复过程?

A7: 监控恢复过程的方法:

  • 查看PostgreSQL日志
  • 使用系统监控工具监控资源使用
  • 定期检查恢复进度
  • 记录恢复时间和步骤
  • 监控关键指标的变化

Q8: 恢复后如何处理性能问题?

A8: 恢复后处理性能问题的方法:

  • 执行真空清理和重新索引
  • 分析查询计划
  • 调整系统配置参数
  • 优化慢查询
  • 监控性能变化趋势
  • 考虑扩容或优化架构