Skip to content

PostgreSQL 经典故障经验教训

监控告警篇

1. 磁盘空间监控不可忽视

经验教训:WAL日志目录磁盘空间耗尽导致数据库挂起的故障,暴露了监控配置的不足。

最佳实践

  • 配置全面的磁盘空间监控,包括数据目录、WAL日志目录、归档目录和临时目录
  • 设置合理的告警阈值,建议磁盘使用率超过80%时触发告警
  • 配置多级告警机制,包括邮件、短信和电话告警
  • 定期检查监控规则的有效性

实施建议

bash
# 使用Prometheus + Grafana监控磁盘空间
# Prometheus配置示例
- job_name: 'node'
  static_configs:
    - targets: ['node-exporter:9100']

# Grafana告警规则示例
ALERT DiskSpaceWarning
  IF (node_filesystem_size_bytes - node_filesystem_free_bytes) / node_filesystem_size_bytes * 100 > 80
  FOR 5m
  LABELS { severity = "warning" }
  ANNOTATIONS {
    summary = "磁盘空间警告",
    description = "{{ $labels.instance }} 的 {{ $labels.mountpoint }} 分区使用率超过80%"
  }

2. 监控指标需覆盖关键组件

经验教训:主从复制延迟问题未及时发现,导致从库数据严重过期。

最佳实践

  • 监控复制延迟、WAL发送和接收状态
  • 监控数据库连接数、慢查询数和锁等待
  • 监控PostgreSQL后台进程状态
  • 监控系统资源使用情况(CPU、内存、I/O、网络)

实施建议

sql
-- 使用pg_stat_statements监控慢查询
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

-- 使用pg_stat_replication监控复制状态
SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, 
       now() - pg_last_xact_replay_timestamp() AS replication_delay
FROM pg_stat_replication;

备份恢复篇

1. 备份策略需完善

经验教训:WAL日志归档失败导致WAL日志无法清理,最终引发磁盘空间问题。

最佳实践

  • 实施3-2-1备份策略:3份备份,2种不同介质,1份异地存储
  • 定期测试备份的可恢复性
  • 配置备份监控和告警
  • 区分全量备份和增量备份

实施建议

bash
# 使用pg_probackup配置自动备份
pg_probackup stanza-create -B /path/to/backup --stanza postgres
pg_probackup backup -B /path/to/backup --stanza postgres -b full
pg_probackup backup -B /path/to/backup --stanza postgres -b incr

# 定期测试恢复
pg_probackup restore -B /path/to/backup --stanza postgres --recovery-target-time '2026-01-01 12:00:00'

2. WAL日志管理需谨慎

经验教训:WAL日志保留策略不当导致磁盘空间耗尽。

最佳实践

  • 根据备份策略设置合理的WAL日志保留时间
  • 配置自动清理机制
  • 监控WAL日志生成速率
  • 考虑使用WAL压缩

实施建议

sql
-- 配置WAL日志保留
ALTER SYSTEM SET wal_keep_size = '2GB';

-- 配置归档命令
ALTER SYSTEM SET archive_command = 'rsync -a %p /path/to/archive/%f';

-- 配置WAL压缩
ALTER SYSTEM SET wal_compression = 'on';

-- 重新加载配置
SELECT pg_reload_conf();

配置管理篇

1. 参数配置需验证

经验教训:配置参数未验证导致性能问题。

最佳实践

  • 配置变更前在测试环境验证
  • 使用配置管理工具管理数据库配置
  • 记录所有配置变更
  • 定期审查配置合理性

实施建议

bash
# 使用Ansible管理PostgreSQL配置
# Ansible playbook示例
- name: Configure PostgreSQL parameters
  hosts: postgres_servers
  become: yes
  tasks:
    - name: Update postgresql.conf
      lineinfile:
        path: /var/lib/pgsql/15/data/postgresql.conf
        regexp: '^shared_buffers'
        line: 'shared_buffers = 2GB'
      notify: restart postgresql

  handlers:
    - name: restart postgresql
      systemd:
        name: postgresql-15
        state: restarted

2. 自动维护需重视

经验教训:自动统计信息收集配置不当导致索引失效。

最佳实践

  • 启用自动清理和分析
  • 为大表配置专门的自动维护参数
  • 监控自动维护任务的执行情况
  • 定期手动执行VACUUM和ANALYZE

实施建议

sql
-- 配置自动维护
ALTER SYSTEM SET autovacuum = on;
ALTER SYSTEM SET autovacuum_max_workers = 3;
ALTER SYSTEM SET autovacuum_naptime = '1min';
ALTER SYSTEM SET autovacuum_analyze_scale_factor = 0.05;

-- 为大表配置专门参数
ALTER TABLE large_table SET (
  autovacuum_analyze_scale_factor = 0.02,
  autovacuum_vacuum_scale_factor = 0.05
);

权限管理篇

1. 最小权限原则必须遵循

经验教训:权限配置错误导致数据泄露风险。

最佳实践

  • 遵循最小权限原则
  • 使用角色管理权限
  • 定期审查用户权限
  • 配置详细的权限审计

实施建议

sql
-- 创建角色而非直接授予用户权限
CREATE ROLE readonly WITH NOSUPERUSER NOCREATEDB NOCREATEROLE LOGIN;
GRANT CONNECT ON DATABASE mydb TO readonly;
GRANT USAGE ON SCHEMA public TO readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
ALTER DEFAULT PRIVILEGES GRANT SELECT ON TABLES IN SCHEMA public TO readonly;

-- 定期审查权限
SELECT grantee, privilege_type, table_name 
FROM information_schema.role_table_grants 
WHERE grantee NOT IN ('postgres', 'public');

2. 安全审计不可缺少

经验教训:权限变更未审计导致安全事件追查困难。

最佳实践

  • 启用详细的安全审计日志
  • 监控异常访问行为
  • 定期分析审计日志
  • 配置审计日志的保留策略

实施建议

sql
-- 启用审计日志
ALTER SYSTEM SET log_statement = 'all';
ALTER SYSTEM SET log_connections = on;
ALTER SYSTEM SET log_disconnections = on;
ALTER SYSTEM SET log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h ';
ALTER SYSTEM SET log_duration = on;

-- 重新加载配置
SELECT pg_reload_conf();

性能优化篇

1. 索引设计需合理

经验教训:索引设计不当导致查询性能急剧下降。

最佳实践

  • 根据查询模式设计索引
  • 避免过多冗余索引
  • 定期分析索引使用情况
  • 考虑使用部分索引和表达式索引

实施建议

sql
-- 分析索引使用情况
SELECT relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch 
FROM pg_stat_user_indexes 
ORDER BY idx_scan ASC;

-- 创建合适的索引
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);

-- 使用部分索引
CREATE INDEX idx_orders_status ON orders(status) WHERE status = 'active';

-- 使用表达式索引
CREATE INDEX idx_users_lower_email ON users(lower(email));

2. 事务管理需优化

经验教训:长事务导致锁竞争和性能问题。

最佳实践

  • 尽量缩短事务长度
  • 避免在事务中执行耗时操作
  • 配置合理的事务超时
  • 监控长时间运行的事务

实施建议

sql
-- 配置事务超时
ALTER SYSTEM SET statement_timeout = '60s';
ALTER SYSTEM SET idle_in_transaction_session_timeout = '300s';

-- 监控长时间运行的事务
SELECT pid, usename, datname, query_start, now() - query_start AS duration, query 
FROM pg_stat_activity 
WHERE state <> 'idle' 
  AND now() - query_start > interval '5 minutes' 
ORDER BY duration DESC;

高可用篇

1. 复制配置需完善

经验教训:主从复制配置不当导致复制延迟。

最佳实践

  • 配置合适的复制参数
  • 监控复制状态
  • 测试故障转移流程
  • 考虑使用多副本架构

实施建议

sql
-- 主库配置
ALTER SYSTEM SET max_wal_senders = 10;
ALTER SYSTEM SET wal_level = 'replica';
ALTER SYSTEM SET synchronous_commit = 'remote_write';

-- 从库配置
ALTER SYSTEM SET hot_standby = on;
ALTER SYSTEM SET hot_standby_feedback = on;
ALTER SYSTEM SET max_worker_processes = 8;
ALTER SYSTEM SET max_parallel_workers = 8;

-- 重新加载配置
SELECT pg_reload_conf();

2. 故障转移需测试

经验教训:故障转移流程未测试导致故障恢复时间延长。

最佳实践

  • 定期测试故障转移流程
  • 确保故障转移自动化
  • 测试数据一致性
  • 验证应用程序切换逻辑

实施建议

bash
# 使用Patroni进行自动故障转移
# Patroni配置示例
scope: postgres-cluster
namespace: /db/
name: postgres-1

restapi:
  listen: 0.0.0.0:8008
  connect_address: 192.168.1.101:8008

etcd:
  host: 192.168.1.100:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        wal_level: replica
        hot_standby: "on"
        wal_keep_size: 2GB

常见问题(FAQ)

Q1:如何建立有效的监控体系?

A1:可以采取以下步骤:

  1. 识别关键监控指标
  2. 选择合适的监控工具(如Prometheus + Grafana)
  3. 配置合理的告警阈值
  4. 建立多级告警机制
  5. 定期审查监控规则

Q2:如何优化PostgreSQL性能?

A2:可以从以下几个方面入手:

  1. 优化配置参数
  2. 合理设计索引
  3. 优化查询语句
  4. 管理长事务
  5. 配置合理的自动维护

Q3:如何确保数据库安全性?

A3:可以采取以下措施:

  1. 遵循最小权限原则
  2. 启用安全审计
  3. 定期更新和补丁
  4. 配置网络访问控制
  5. 使用加密连接

Q4:如何设计可靠的备份策略?

A4:可以遵循以下原则:

  1. 实施3-2-1备份策略
  2. 结合全量备份和增量备份
  3. 定期测试备份恢复
  4. 配置备份监控和告警
  5. 考虑异地备份

Q5:如何管理WAL日志?

A5:可以采取以下措施:

  1. 根据备份策略设置合理的保留时间
  2. 配置自动清理机制
  3. 监控WAL日志生成速率
  4. 考虑使用WAL压缩
  5. 确保归档命令可靠

Q6:如何优化索引设计?

A6:可以采取以下步骤:

  1. 分析查询模式
  2. 避免过多冗余索引
  3. 定期分析索引使用情况
  4. 考虑使用部分索引和表达式索引
  5. 使用CONCURRENTLY创建和重建索引

Q7:如何处理长事务?

A7:可以采取以下措施:

  1. 尽量缩短事务长度
  2. 配置合理的事务超时
  3. 监控长时间运行的事务
  4. 避免在事务中执行耗时操作
  5. 使用合适的事务隔离级别

Q8:如何测试故障转移?

A8:可以采取以下步骤:

  1. 制定详细的故障转移测试计划
  2. 在测试环境定期演练
  3. 测试数据一致性
  4. 验证应用程序切换逻辑
  5. 记录测试结果并优化流程