原创

告别单点故障!MySQL Group Replication如何重塑金融级数据库架构

温馨提示:
本文最后更新于 2025年03月13日,已超过 37 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

 

MySQL Group Replication(组复制)是 MySQL 提供的一种高级高可用解决方案,基于 Paxos 协议实现多主复制,适合对数据一致性和高可用性要求高的场景。

一、技术原理

1.1架构设计原理

1.1.1 多主复制机制

  • Paxos共识算法
    通过分布式投票机制保证事务提交的原子性,集群中超过半数节点确认即视为提交成功
  • 数据流向模型
    https://via.placeholder.com/600x300?text=Multi-Master+Replication+Flow
    • 本地事务处理:各节点独立执行SQL
    • 全局事务协调:通过Group Communication Framework(GCF)广播事务事件
    • 冲突解决方案:基于transaction_write_set_extraction算法检测冲突,采用版本向量(Version Vectors)解决写入冲突

1.1.2 故障转移机制

  • 智能心跳检测
    每3秒发送Gossip消息,节点失联超过group_replication_unavailable_timeout(默认30秒)触发故障判定
  • 自动选举算法
    基于Raft协议的领导者选举,新主节点从候选节点中选择GROUP_REPLICATION_ADMIN角色持有者

1.2. 适用场景

  • 高可用需求:需要自动故障转移和多主复制能力。
  • 数据一致性要求高:如金融、支付等关键业务场景。
  • 多写场景:需要多个节点同时处理写请求。

二.部署组复制

2.1. 服务器信息

主机

IP 地址

操作系统

角色

master

192.168.3.28

Ubuntu 22.04

主节点

node1

192.168.3.29

Ubuntu 22.04

从节点

node2

192.168.3.30

Ubuntu 22.04

从节点

2.2. 配置 my.cnf

在三台主机上创建 MySQL 容器并映射目录:

sudo mkdir -p /opt/mysql/data /opt/mysql/conf /opt/mysql/files

在三台主机上配置 /opt/mysql/conf/my.cnf,确保每个主机的 server-id 不同:

[mysqld]
# 设置服务器ID,确保在复制环境中每个MySQL实例的ID是唯一的
server-id = 1
# 指定MySQL服务监听的端口号
port = 3309
# 禁用指定的存储引擎,防止使用这些可能不适合当前应用场景的存储引擎
disabled_storage_engines = "MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
# 设置默认时区为东八区(北京时间)
default_time_zone = "+8:00"
# 设置事务隔离级别为读已提交,适合大多数需要避免脏读的应用场景
transaction_isolation = READ-COMMITTED
# 启用二进制日志记录,用于数据恢复和复制
log-bin = mysql-bin
# 设置二进制日志格式为ROW,提供更精确的数据变更记录
binlog_format = ROW
# 在ROW格式下,记录完整的行图像,便于数据恢复
binlog_row_image = FULL
# 设置二进制日志过期时间为1209600秒(即14天),帮助控制磁盘使用
binlog_expire_logs_seconds = 1209600
# 将master信息存储在表中而不是文件中,提高可靠性和管理便利性
master_info_repository = TABLE
# 将relay log信息存储在表中而不是文件中,提高可靠性和管理便利性
relay_log_info_repository = TABLE
# 启用从库更新的日志记录,支持基于GTID的复制
log_replica_updates = ON
# 启用中继日志恢复功能,在崩溃后自动恢复
relay_log_recovery = 1
# 跳过特定类型的错误,例如DDL语句存在的错误
replica_skip_errors = ddl_exist_errors
# 在每次事务提交时都将缓存的日志刷新到磁盘,保证ACID属性中的D(持久性)
innodb_flush_log_at_trx_commit = 1
# 每次事务提交时同步二进制日志到磁盘,保证数据一致性
sync_binlog = 1
# 设置事务写集提取算法为XXHASH64,用于并行复制和冲突检测
transaction_write_set_extraction = XXHASH64
# 启用全局事务ID模式,允许基于GTID的复制
gtid_mode = on
# 强制GTID的一致性,不允许执行破坏GTID连续性的操作
enforce_gtid_consistency = ON

2.3. 启动容器

在三台主机上执行以下命令启动 MySQL 容器:

sudo docker run \
  -u root \
  --network=host \
  --restart=always \
  --name mysql8 \
  -v /opt/mysql/conf/my.cnf:/etc/mysql/my.cnf \
  -v /opt/mysql/files:/var/lib/mysql-files \
  -v /opt/mysql/data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=q1w2E#R$ \
  -d mysql:8.0.27

2.4. 创建用户

执行以下命令进入MySQL容器

sudo docker exec -it mysql8 /bin/bash
mysql -uroot -p -P3309

在三台主机上创建复制用户:

SET SQL_LOG_BIN=0;

CREATE USER rpl_user@'%' IDENTIFIED WITH mysql_native_password BY 'PassWord123_';
GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
GRANT CONNECTION_ADMIN ON *.* TO rpl_user@'%';
GRANT BACKUP_ADMIN ON *.* TO rpl_user@'%';
GRANT GROUP_REPLICATION_STREAM ON *.* TO rpl_user@'%';
GRANT SELECT ON performance_schema.replication_group_members TO rpl_user@'%';
FLUSH PRIVILEGES;

SET SQL_LOG_BIN=1;

三台主机将用户凭据提供给服务器以用于分布式恢复

CHANGE REPLICATION SOURCE TO SOURCE_USER='rpl_user', SOURCE_PASSWORD='PassWord123_'  FOR CHANNEL 'group_replication_recovery';

2.5. 配置 Group Replication

在三台主机安装插件

# 安装插件
INSTALL PLUGIN group_replication SONAME 'group_replication.so'; 
# 查看插件
SHOW PLUGINS;

在三台主机的 my.cnf 中增加 Group Replication 参数:

# master
group_replication_group_name = "7cf70110-59f9-11ee-a293-246e967fa518"
group_replication_start_on_boot = off
group_replication_local_address = "192.168.3.28:33061"
group_replication_group_seeds = "192.168.3.28:33061,192.168.3.29:33061,192.168.3.30:33061"
group_replication_bootstrap_group = off

# node1
group_replication_group_name = "7cf70110-59f9-11ee-a293-246e967fa518"
group_replication_start_on_boot = off
group_replication_local_address = "192.168.3.29:33061"
group_replication_group_seeds = "192.168.3.28:33061,192.168.3.29:33061,192.168.3.30:33061"
group_replication_bootstrap_group = off

# node2
group_replication_group_name = "7cf70110-59f9-11ee-a293-246e967fa518"
group_replication_start_on_boot = off
group_replication_local_address = "192.168.3.30:33061"
group_replication_group_seeds = "192.168.3.28:33061,192.168.3.29:33061,192.168.3.30:33061"
group_replication_bootstrap_group = off

三台主机重启容器

sudo docker restart mysql8

登录mysql之后查看参数

SHOW VARIABLES LIKE 'group_replication%';

2.6. 启动集群

在 master 上启动集群:

SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION USER='rpl_user', PASSWORD='PassWord123_';
SET GLOBAL group_replication_bootstrap_group=OFF;

2.7. 加入集群

在 node1 和 node2 上加入集群:

START GROUP_REPLICATION USER='rpl_user', PASSWORD='PassWord123_';

2.8. 验证集群状态

查看集群状态和事件记录:

SELECT * FROM performance_schema.replication_group_members;
SHOW BINLOG EVENTS;

三.性能优化

在高并发场景下,调整innodb_flush_log_at_trx_commit和sync_binlog这两个参数可以在性能和数据一致性之间找到一个平衡点。

3.1innodb_flush_log_at_trx_commit

这个参数控制着InnoDB存储引擎在事务提交时如何写入和刷新日志缓冲区的数据到磁盘。

  • 默认值(1):每次事务提交时都将日志缓冲区的内容写入日志文件,并且同步到磁盘。这是最安全的设置,能确保最高的数据持久性,但会对性能产生较大影响。
  • 值为0:每秒将日志缓冲区的数据写入日志文件并同步到磁盘一次,而不是每次事务提交都执行此操作。这提高了性能,但在数据库崩溃时可能会丢失一秒内的事务数据。
  • 值为2:每次事务提交时都将日志缓冲区的数据写入日志文件,但并不强制同步到磁盘。这意味着如果操作系统崩溃,可能会丢失最后一段时间的数据,但相比值为0的情况要少一些。

建议调整

  • 如果你的应用可以接受一定程度的数据丢失风险(例如某些非关键交易系统),为了提高性能,可以选择将此参数设置为2。这样既保证了较高的事务处理速度,又能在大多数情况下提供足够的数据安全性。
  • 对于那些要求极高数据一致性和持久性的应用(如金融系统),则应保持默认值1不变。

3.2sync_binlog

该参数决定了MySQL在二进制日志中记录了多少次事务后调用fsync()函数将其同步到磁盘。

  • 默认值(1):每次事务提交都会触发同步操作,保证了二进制日志的最大安全性,但是会显著降低写入性能。
  • 值大于1:指定每次同步前需要累积多少次事务提交,比如100表示每100次事务提交后同步一次。这种方式可以提升性能,但增加了数据丢失的风险。
  • 值为0:由操作系统决定何时将二进制日志缓存中的内容同步到磁盘。这种方式可能带来最佳的写入性能,但也是最不安全的选择,因为一旦发生故障,可能导致大量未同步的事务丢失。

建议调整

  • 在追求极致性能的情况下,可以考虑将sync_binlog设置为一个较大的数值(如100或更高),但这意味着你需要接受更高的数据丢失风险。
  • 对于需要严格保证数据一致性的环境,应该维持默认值1,尽管这样做会影响性能。

四、注意事项

  1. 网络配置

如果各节点不在同一子网,需在my.cnf文件中配置 group_replication_ip_allowlist 参数,允许节点间通信。

group_replication_ip_allowlist = "127.0.0.1,192.168.3.28,192.168.3.29,192.168.3.30"
  1. 监控与维护

使用 MySQL Performance Schema 和监控工具(如 Prometheus + Grafana)实时监控集群状态。

正文到此结束
本文目录