← 返回 MYSQL 列表

高可用架构

高可用架构

一、读写分离

1.1 读写分离架构

            应用
            │
       ┌────┴────┐
       │ 负载均衡 │
       └────┬────┘
            │
    ┌───────┴────────┐
    │                │
  写请求           读请求
    │                │
    ▼                ▼
  主库(Master)     从库(Slave)
                    │
            ┌───────┴───────┐
            │               │
          从库1           从库2

1.2 实现方案

sql
-- 方案1:应用层实现(配置多数据源)
-- 在代码中区分读写操作,写操作走主库,读操作走从库

-- 方案2:使用中间件

-- MySQL Router(官方)
mysql-router --bootstrap master:3306 --user mysql
-- 自动路由读写请求

-- ProxySQL(推荐)
-- 配置 ProxySQL
INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES
(0, '192.168.1.100', 3306),  -- 主库(写组)
(1, '192.168.1.101', 3306),  -- 从库1(读组)
(1, '192.168.1.102', 3306);  -- 从库2(读组)

-- 配置读写分离规则
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup) VALUES
(1, 1, '^SELECT', 1),    -- SELECT 语句走读组
(2, 1, '^INSERT|UPDATE|DELETE', 0);  -- 写语句走写组

-- 方案3:客户端组件
-- ShardingSphere-JDBC:在 JDBC 层实现
-- 配置见主从复制章节

二、高可用方案

2.1 MHA(Master High Availability)

MHA 是目前比较成熟的主从高可用方案,能在 30 秒内完成主库故障切换。

架构:
  Manager 节点(监控)
       │
  ┌────┴────┐
  │         │
主库      从库1(备用主库)
           │
          从库2

MHA 工作原理

故障检测 → 选举新主库 → 补齐 relay log → 提升为主库 → 切换 VIP/配置
bash
# MHA 配置示例 (/etc/mha/app1.cnf)
[server default]
manager_log=/var/log/mha/manager.log
manager_workdir=/var/log/mha
user=root
password=xxx
ssh_user=root
repl_user=repl
repl_password=xxx

[server1]
hostname=192.168.1.100
master_binlog_dir=/var/log/mysql

[server2]
hostname=192.168.1.101
candidate_master=1    # 设置为候选主库

[server3]
hostname=192.168.1.102
no_master=1           # 不作为候选主库

# 启动 MHA Manager
masterha_manager --conf=/etc/mha/app1.cnf

MHA 故障切换流程

1. Manager 检测到主库不可用(ping/连接超时)
2. 尝试 SSH 连接主库确认
3. 从所有从库中选一个数据最新的作为新主库
4. 从其他从库补齐该从库缺失的 relay log
5. 提升该从库为新主库
6. 将其他从库指向新主库
7. 移除旧主库 VIP(如果有),绑定到新主库
8. 发送告警通知

2.2 Keepalived + 主从切换

bash
# 主库 VIP 配置(/etc/keepalived/keepalived.conf)
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass 1111
    }

    virtual_ipaddress {
        192.168.1.200/24  # VIP
    }

    # MySQL 健康检查
    track_script {
        chk_mysql
    }
}

# 健康检查脚本
vrrp_script chk_mysql {
    script "/etc/keepalived/check_mysql.sh"
    interval 2
    weight -20
}
bash
#!/bin/bash
# /etc/keepalived/check_mysql.sh
# MySQL 健康检查

mysql -u root -p'xxx' -e "SELECT 1" > /dev/null 2>&1
if [ $? -ne 0 ]; then
    # MySQL 挂了,尝试重启
    systemctl restart mysql

    sleep 5

    # 重启失败,让 Keepalived 降权触发切换
    mysql -u root -p'xxx' -e "SELECT 1" > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        exit 1
    fi
fi

exit 0

2.3 MySQL InnoDB Cluster(官方方案)

MySQL 5.7+ 提供的官方高可用方案,基于 Group Replication。

架构:
  MySQL Router
       │
  ┌────┼────┐
  │    │    │
  │    │    │
  M1──M2──M3(Group Replication)
  (Primary) (Secondary) (Secondary)
sql
-- 配置 Group Replication

-- 每个节点的配置文件
[mysqld]
server_id = 1
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_format = ROW
log_slave_updates = ON
transaction_write_set_extraction = XXHASH64
loose-group_replication_group_name = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
loose-group_replication_start_on_boot = OFF
loose-group_replication_local_address = "192.168.1.100:33061"
loose-group_replication_group_seeds = "192.168.1.100:33061,192.168.1.101:33061,192.168.1.102:33061"
loose-group_replication_bootstrap_group = OFF
loose-group_replication_single_primary_mode = ON  -- 单主模式

-- 创建复制用户
SET SQL_LOG_BIN=0;
CREATE USER 'repl'@'%' IDENTIFIED BY 'xxx';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
SET SQL_LOG_BIN=1;

-- 引导第一个节点
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='xxx'
FOR CHANNEL 'group_replication_recovery';
START GROUP_REPLICATION;

2.4 高可用方案对比

方案 切换时间 优点 缺点
MHA 10~30秒 成熟稳定、MySQL 原生兼容 需额外部署、有数据丢失风险
Keepalived 5~30秒 简单、VIP 切换快 需要脚本配合、无数据一致性保证
InnoDB Cluster 自动切换 官方方案、强一致性 复杂度高、版本限制
Orchestrator 秒级 自动管理、Web 界面 需 Raft 集群
ProxySQL + MHA 秒级 对应用透明 维护成本高

三、故障切换与容灾设计

3.1 主库故障切换流程

sql
-- 手动切换步骤

-- 步骤1:确认主库不可用
-- 通过监控系统或手动登录确认

-- 步骤2:从从库中选择新主库
-- 选数据最新的从库
SHOW SLAVE STATUS\G
-- 比较各从库的 Master_Log_File 和 Read_Master_Log_Pos

-- 最好的候选从库:
-- 数据最新(binlog 位置最大)
-- 硬件配置最好
-- 网络延迟最小

-- 步骤3:提升候选从库为新主库
STOP SLAVE;
RESET SLAVE ALL;
SET GLOBAL read_only = OFF;

-- 步骤4:切换其他从库到新主库
CHANGE MASTER TO
    MASTER_HOST = '新主库IP',
    MASTER_USER = 'repl',
    MASTER_PASSWORD = 'xxx',
    MASTER_LOG_FILE = 'mysql-bin.00000X',
    MASTER_LOG_POS = YYYYY;
START SLAVE;

-- 步骤5:更新应用连接配置
-- 修改应用数据源,指向新主库

3.2 容灾设计

同城双活:
  机房A(主)←→ 机房B(备)
  距离:< 50km
  延迟:< 5ms

两地三中心:
  城市A:主机房
  城市A:同城备份机房
  城市B:异地灾备机房(异步复制)

容灾策略

策略 RPO RTO 成本
同城双活 < 1秒 秒级
异地异步备份 分钟级 小时级
两地三中心 秒级 分钟级 极高
云平台跨可用区 < 1秒 自动化 按需

四、实战案例

案例1:ProxySQL + MHA 高可用架构

bash
# ProxySQL 配置

# 1. 添加 MySQL 服务器
INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES
(0, '192.168.1.100', 3306),   # 写组
(0, '192.168.1.101', 3306),   # 写组(备用)
(1, '192.168.1.101', 3306),   # 读组
(1, '192.168.1.102', 3306);   # 读组

# 2. 配置监控用户
UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_username';
UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_password';

# 3. 配置读写分离规则
INSERT INTO mysql_query_rules
(rule_id,active,match_pattern,destination_hostgroup,apply) VALUES
(1,1,'^SELECT.*FOR UPDATE',0,1),   # SELECT FOR UPDATE 走写
(2,1,'^SELECT',1,1),               # SELECT 走读
(3,1,'^INSERT|^UPDATE|^DELETE',0,1);  # 写语句走写

# 4. MHA 切换后自动更新 ProxySQL
# MHA 切换脚本中调用 ProxySQL 管理接口
# mysql -h127.0.0.1 -P6032 -uadmin -padmin -e "
#     DELETE FROM mysql_servers WHERE hostgroup_id = 0 AND hostname = '旧主库IP';
#     INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (0, '新主库IP', 3306);
#     LOAD MYSQL SERVERS TO RUNTIME;
# "

案例2:数据库故障演练

sql
-- 故障演练流程

-- 场景1:模拟主库宕机
-- 1. 停止主库 MySQL
systemctl stop mysql

-- 2. 观察 MHA/Keepalived 是否自动切换
-- 3. 验证读写是否正常
-- 4. 记录切换时间

-- 场景2:模拟网络分区
-- 1. 主库网络断开
iptables -A INPUT -s 从库IP -j DROP

-- 2. 观察复制状态
-- 3. 恢复网络后验证数据一致性

-- 场景3:模拟从库延迟
-- 1. 从库上执行大查询
SELECT *, SLEEP(1) FROM big_table;

-- 2. 观察延迟监控
-- 3. 检查读请求是否切换到其他从库

-- 演练结果记录
-- 切换时间、数据丢失量、业务影响时长

总结

方案 适用场景 关键点
读写分离 读多写少 中间件负载均衡、延迟处理
MHA 主从架构 30秒切换、需要 SSH、可能丢数据
Keepalived 简单主备 VIP 切换、配合健康检查
InnoDB Cluster 强一致性 Group Replication、官方支持
两地三中心 极端容灾 异步复制、RPO/RTO 均衡

设计原则

  • 没有完美的 HA 方案,选择最适合业务场景的
  • 定期进行故障演练,验证 HA 方案的有效性
  • 监控和告警比 HA 方案本身更重要
  • 做好"最坏情况"预案(全量备份恢复)