数据库高可用架构设计与灾备方案

摘要

本文将全面剖析数据库高可用架构的设计原理与实施路径,涵盖主从复制、集群方案、数据同步、容灾切换等核心技术。详细解读MGR、InnoDB Cluster、PG流复制等主流方案,提供从单机房部署到异地多活的全套解决方案,包含详细的配置示例、监控指标和故障演练方案。适合需要构建金融级可靠数据库服务的技术团队。


一、高可用基础架构

1. 复制技术矩阵对比

技术类型 同步方式 数据一致性 故障恢复时间 适用场景
异步复制 异步 最终一致 分钟级 跨地域副本
半同步复制 半同步 强一致 秒级 同城双机房
组复制(MGR) 同步组 强一致 秒级 金融交易系统
物理流复制(PG) 同步/异步 可配置 秒级 关键业务数据库

2. 主流方案选型指南

MySQL高可用方案对比

1. **主从复制+VIP**  
   - 优点:部署简单,资源消耗低  
   - 缺点:需额外工具管理VIP,脑裂风险  

2. **MHA(MySQL Master High Availability)**  
   - 优点:自动故障转移,支持binlog补偿  
   - 缺点:需SSH信任关系,已停止维护  

3. **InnoDB Cluster(MySQL Shell)**  
   - 优点:官方方案,自动选主  
   - 缺点:需要组复制支持  

4. **Galera Cluster**  
   - 优点:多主架构,同步复制  
   - 缺点:写扩展性差,DDL阻塞  

PostgreSQL高可用方案

# 基于Patroni的HA方案
patroni \
  --datadir=/var/lib/postgresql/12/main \
  --config-file=/etc/patroni.yml \
  --dcs=etcd://10.0.0.1:2379

二、MySQL高可用实战

1. 组复制(MGR)部署

集群初始化配置

# my.cnf配置示例
[mysqld]
server_id = 1
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_checksum = NONE
log_bin = binlog
log_slave_updates = ON
binlog_format = ROW
master_info_repository = TABLE
relay_log_info_repository = TABLE
transaction_write_set_extraction = XXHASH64
slave_parallel_workers = 8
slave_preserve_commit_order = 1
plugin_load_add = 'group_replication.so'
group_replication_group_name = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot = OFF
group_replication_local_address = "node1:33061"
group_replication_group_seeds = "node1:33061,node2:33061,node3:33061"
group_replication_bootstrap_group = OFF

集群启动流程

-- 首个节点引导集群
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;

-- 其他节点加入
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='password' 
  FOR CHANNEL 'group_replication_recovery';
START GROUP_REPLICATION;

2. 读写分离实现

ProxySQL配置示例

-- 定义服务器组
INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES 
  (10,'master-node',3306),
  (20,'slave1-node',3306),
  (20,'slave2-node',3306);

-- 配置路由规则
INSERT INTO mysql_query_rules (rule_id,active,match_pattern,destination_hostgroup,apply) VALUES
  (1,1,'^SELECT.*FOR UPDATE',10,1),
  (2,1,'^SELECT',20,1),
  (3,1,'^INSERT',10,1),
  (4,1,'^UPDATE',10,1),
  (5,1,'^DELETE',10,1);

-- 设置健康检查
UPDATE global_variables SET variable_value='2000' WHERE variable_name='mysql-monitor_slave_lag_when_null';
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;

三、PostgreSQL高可用方案

1. 流复制部署

主库配置

# postgresql.conf
wal_level = replica
max_wal_senders = 10
wal_keep_size = 1024
hot_standby = on

# pg_hba.conf
host replication repuser 10.0.0.0/24 md5

备库搭建命令

# 基础备份
pg_basebackup -h master-host -U repuser -D /var/lib/postgresql/12/main -P -Xs -R

# 配置standby.signal
touch $PGDATA/standby.signal

# recovery.conf自动生成内容
primary_conninfo = 'host=master-host port=5432 user=repuser password=secret'

2. 自动故障转移方案

Patroni配置示例

# /etc/patroni.yml
scope: pg-cluster
namespace: /service/
name: pg-node1

restapi:
  listen: 0.0.0.0:8008
  connect_address: 10.0.0.1:8008

etcd:
  hosts: 10.0.0.1:2379,10.0.0.2:2379,10.0.0.3:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      parameters:
        max_connections: 100
        shared_buffers: 1GB

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false

四、跨机房容灾方案

1. 同城双活架构

拓扑设计要点

[应用层] 
  ↓
[数据库中间件] → [机房A主库] ↔ 同步复制 ↔ [机房B备库]
  ↓
[全局负载均衡] (基于RTT自动路由)

数据同步验证脚本

import pymysql
from datetime import datetime

def verify_replication(primary_conn, standby_conn):
    with primary_conn.cursor() as p_cur:
        p_cur.execute("SHOW MASTER STATUS")
        binlog_file, binlog_pos = p_cur.fetchone()[:2]
    
    with standby_conn.cursor() as s_cur:
        s_cur.execute(f"SHOW SLAVE STATUS")
        slave_status = s_cur.fetchone()
        
        if (slave_status[1] == binlog_file and 
            slave_status[2] == binlog_pos):
            print(f"[{datetime.now()}] 复制状态正常")
        else:
            print(f"[{datetime.now()}] 复制延迟警告!主库位置:{binlog_file}/{binlog_pos} 从库位置:{slave_status[1]}/{slave_status[2]}")

2. 异地灾备实施

MySQL异步复制配置

# 灾备节点my.cnf
[mysqld]
server_id = 201  # 与主机房区分
log_bin = /var/log/mysql/mysql-bin
relay_log = /var/log/mysql/mysql-relay-bin
read_only = ON
skip_slave_start = ON
log_slave_updates = ON

数据校验方案

-- 使用pt-table-checksum
pt-table-checksum \
  --replicate=test.checksums \
  --recursion-method=hosts \
  h=master-host,u=checksum_user,p=password

-- 校验结果查询
SELECT db, tbl, SUM(this_cnt) AS total_rows, 
       COUNT(*) AS chunks
FROM test.checksums
WHERE master_cnt <> this_cnt OR master_crc <> this_crc
GROUP BY db, tbl;

五、监控与故障处理

1. 关键监控指标

MySQL高可用监控项

指标类别 监控项 告警阈值 采集方式
复制状态 Slave_IO_Running != Yes SHOW SLAVE STATUS
延迟时间 Seconds_Behind_Master > 30秒 性能模式
组复制 Group_replication_primary_member 空值超过10秒 状态变量
网络分区 Group_replication_member_count < 法定节点数 性能模式

PostgreSQL监控项

SELECT client_addr, state, 
       pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes,
       EXTRACT(EPOCH FROM (now() - replay_lag)) AS lag_seconds
FROM pg_stat_replication;

2. 典型故障处理

脑裂场景处理流程

1. [检测] 同时出现多个主库写入成功
2. [隔离] 停止所有应用写入
3. [仲裁] 人工确认最新数据节点
4. [恢复] 以最新节点为基准重建集群
5. [补偿] 使用binlog修复数据差异
6. [验证] 数据一致性检查
7. [复盘] 分析根本原因(通常为网络分区)

数据冲突解决工具

# MySQL使用pt-table-sync修复差异
pt-table-sync --replicate=test.checksums \
  --sync-to-master h=slave-host,u=admin,p=password

# PostgreSQL使用pg_rewind重置备库
pg_rewind --target-pgdata=/var/lib/postgresql/12/main \
  --source-server="host=primary-host user=postgres"

六、灾备演练方案

1. 标准演练流程

演练检查表

- [ ] 提前通知相关业务方
- [ ] 备份当前数据库状态
- [ ] 记录演练开始时间戳
- [ ] 模拟主库宕机(停止mysqld/postgres)
- [ ] 观察监控系统告警
- [ ] 验证自动切换流程
- [ ] 手动介入处理(如需)
- [ ] 验证应用连接恢复
- [ ] 原主库恢复加入集群
- [ ] 生成演练报告

2. 压测方案设计

使用sysbench模拟故障

# 准备测试数据
sysbench oltp_read_write \
  --db-driver=mysql \
  --mysql-host=master-host \
  --mysql-port=3306 \
  --mysql-user=sysbench \
  --mysql-password=password \
  --mysql-db=sbtest \
  --tables=10 \
  --table-size=1000000 \
  prepare

# 运行压力测试(在主库执行时手动kill主库进程)
sysbench oltp_read_write \
  --time=300 \
  --threads=32 \
  --report-interval=5 \
  --db-driver=mysql \
  --mysql-host=master-host \
  --mysql-port=3306 \
  --mysql-user=sysbench \
  --mysql-password=password \
  --mysql-db=sbtest \
  run

结语

构建完善的数据库高可用体系需要遵循以下原则:

  1. 分层防护

    • 前端:连接池重试机制
    • 中间层:读写分离与负载均衡
    • 数据层:自动故障转移
    • 基础设施:网络冗余设计
  2. 定期验证

    • 每季度全链路故障演练
    • 半年度的跨机房切换测试
    • 年度灾备恢复演练
  3. 持续优化

    graph TD
      A[监控告警] --> B[根因分析]
      B --> C[方案设计]
      C --> D[测试验证]
      D --> E[上线实施]
      E --> A
    

"真正的可靠性不是没有故障,而是故障发生时系统能优雅降级并快速恢复。高可用架构的价值就在于此。"

建议将以下内容纳入日常运维规范:

  • 所有生产环境数据库必须配置监控和告警
  • 任何架构变更前需进行故障模式分析(FMEA)
  • 建立完善的变更管理和回滚机制
  • 定期更新应急预案和操作手册