1. 传统主从复制技术架构
传统主从复制的方式是在master节点上执行数据更新事务,而后记录这些事务到binlog中,再将binlog发送到slave节点转储成relay log,在slave节点上再有单独的线程读取这些relay log然后重新执行或应用这些事务,它是shared-nothing的,每个节点都有一份完整的数据副本,其技术流程图如下所示:
- 传统主从复制技术架构图

mysql还提供了半同步复制,这是在传统主从复制的基础上增加了一个同步的步骤,master节点上提交事务前,要先等到slave节点确认收到事务信息才可以(所以前文才说当slave节点响应慢时会影响master节点的事务提交),其技术流程图如下所示:
- 半同步复制技术架构图

2. mgr组复制技术架构
mgr也是shared-nothing的,每个节点都有一份完整的数据副本,mgr可以做到在任何节点、任何时间都能执行读写事务(不含只读事务),不过读写事务要被整个复制组确认后才能提交。如果是只读事务则没有这个限制,任何节点都可以发起及提交。
当读写事务准备提交前,它会向复制组发出一个原子广播,内容包括:该事务修改的数据,及其所对应的writeset(例如,一个执行 update user set age=25 where id=1 的事务,其 writeset 可能记录为:{ "database": "test", "table": "user", "primary_key": "id=1" })。复制组中所有节点要么接收该事务,要么都不接收。如果组中所有节点都接收该事务消息,那么它们都会按照与之前发送事务的相同顺序收到该广播消息。因此,所有组成员都以相同的顺序接收事务的写集,并为事务建立全局顺序。
在多个节点上并行执行的事务是可能产生冲突的,这时候就需要对比判断两个并行事务的writeset来确认,这个过程称为事务认证,也叫做冲突检测。事务冲突检测是行级别的,也就是说两个并行的事务更新同一行时,则视为产生冲突。这时的做法是全局顺序在前面的事务可以成功,所有节点都提交该事务。而全局顺序在后面的事务会失败回滚,各节点会删除该事务。这实际上是个分布式的谁先提交谁先赢得事务的规则。建议:如果经常发生节点间的事务冲突,那最好将这些事务放在同一个节点上执行,这样它们在本地事务并发控制协调下可能都可以提交成功,而不至于由于mgr的冲突检测而导致某个事务总是被回滚。
对于正在应用或外化的事务,mgr允许它们不一定按照原有顺序执行,只要不破坏事务的一致性和有效性即可。mgr默认要求是最终一致性,也就是说当所有事务都应用完毕后,所有节点的数据是一致的。当流量巨大时,事务可能会被外化而导致顺序轻微不一致。例如在多主模式下,一个本地事务在通过认证后会被立即外化,尽管此时可能还有个有这更早全局顺序的远程事务还没被应用,只要mgr的认证线程认为这个事务不会产生冲突即可。在单主模式下,在primary节点上的本地并发事务,在不产生冲突的情况下,其提交和外化的顺序可能和该事物的全局事务顺序有轻微不一致。在secondary节点上,由于没有写事务,因此它们的事务顺序和全局事务顺序是一致的。
下图描述了mgr的组复制协议,可以看到和传统主从复制(及半同步复制)的一些差异。为了简单起见,图中少了共识算法和paxos相关的信息:
- mgr技术架构图

paxos 协议
在 mysql group replication(mgr)中,共识算法基于 paxos 协议,主要用于确保集群中各节点在事务提交等操作上达成一致,其工作过程如下:
事务提议与广播
- 当一个节点上有事务要执行时,该事务在本地执行后,节点会将事务信息,如 writeset 等,通过 paxos 模块广播给 mgr 集群中的各个节点,包括其自身。这个过程类似于 paxos 协议中的提议阶段,每个节点都可以提出事务提议。
冲突检测与解决
- 各个节点在接收到事务信息后,会各自进行冲突检测。如果多个事务修改了同一行数据,mgr 会采用 “先提交者获胜” 的策略,后提交的事务将被回滚。在多主模式下,节点会根据版本号,如 trx_id 或行级时间戳等,判断最新版本,拒绝旧版本的事务。如果是单主模式,当主节点在应用来自前一个主节点的中继日志时,不进行冲突检测,其他情况则需要进行冲突检测。
具体处理流程(3 节点场景)
假设集群节点为 a、b、c,事务 t 在节点 a 发起:
事务执行与广播:节点 a 执行 t 并生成 writeset,广播给 b 和 c。
多数派初步确认:节点 a 和 b 检测到 t 的 writeset 与本地历史无冲突,返回 “确认”(已满足多数派 2/3)。
第 3 节点检测到冲突:节点 c 发现 t 的 writeset 与本地已提交的事务 t’ 冲突(例如 t 和 t’ 都修改了
user.id=1),返回 “冲突”。- 全集群事务回滚:
- 节点 a 收到 c 的 “冲突” 反馈后,判定 t 为冲突事务,立即在本地回滚 t。
- 同时向 b 和 c 广播 “事务 t 冲突,需回滚” 的指令。
- 节点 b 即使已初步确认无冲突,也会执行回滚(放弃 t 的执行)。
- 最终,a、b、c 均不保留 t 的修改,集群数据保持一致。
多数派确认
- paxos 协议的核心是 “多数派确认” 机制。在 mgr 中,仅当多数节点,即超过半数的节点确认接收并接受该写集合后,事务才会最终提交。例如,在一个 3 节点的集群中,至少需要 2 个节点确认后事务才能提交。这确保了只有被多数节点认可的写操作才会被最终执行,从而避免了数据丢失。
状态同步与主节点选举
- 当新的事务提交或者主节点发生变化时,节点之间需要进行状态同步。例如,当主节点不可用时,剩余节点会通过 paxos 协议选举新的主节点。选举过程中,需满足 “多数存活” 条件,如 3 节点集群中至少 2 节点存活。新主节点会同步已提交的全局事务,确保数据完整性后再对外提供服务。
原子广播
- mgr 基于 paxos 的原子广播特性,确保所有节点要么全部接收消息,要么全部不接收。这意味着在事务广播过程中,不会出现部分节点接收到消息并执行,而另一部分节点未接收到消息的情况,从而避免了数据不一致。
3.mgr搭建
| 角色 | ip |
| 主 | 192.168.160.205 |
| 从 | 192.168.160.203 |
| 从 | 192.168.160.206 |
安装mysql(三个)
创建数据库目录
mkdir -p /data/mysql/mysqldata/mysql3306/{data,logs,binlog,relaylog,sock,backup,tmp}
mkdir -p /data/mysql/mysqlbase
touch /data/mysql/mysqldata/mysql3306/logs/error.log
解压安装包
tar -xvf mysql-8.0.43-linux-glibc2.17-x86_64.tar.xz -c /data/mysql/mysqlbase/ cd /data/mysql/mysqlbase/ mv mysql-8.0.43-linux-glibc2.17-x86_64/ mysql3306
添加配置文件
cd /data/mysql/mysqldata/mysql3306/ vim my8.cnf [mysql] default-character-set=utf8mb4 [mysqld] port=3306 character-set-server=utf8mb4 default-storage-engine=innodb general_log= on max_connections=100 interactive_timeout = 120 wait_timeout = 120 ###dir basedir=/data/mysql/mysqlbase/mysql3306 datadir=/data/mysql/mysqldata/mysql3306/data pid-file=/data/mysql/mysqldata/mysql3306/sock/mysqld.pid socket = /data/mysql/mysqldata/mysql3306/sock/mysql.sock tmpdir=/data/mysql/mysqldata/mysql3306/tmp log-error=/data/mysql/mysqldata/mysql3306/logs/error.log ###slow sql slow_query_log = on slow_query_log_file = /data/mysql/mysqldata/mysql3306/logs/slow.log long_query_time = 0.5 ###safe #skip-grant-tables skip-name-resolve ###memory size binlog_cache_size = 4096 max_binlog_cache_size = 256m table_open_cache=2000 tmp_table_size=256m key_buffer_size=256m read_buffer_size=4m read_rnd_buffer_size=32m innodb_log_buffer_size=32m innodb_buffer_pool_size=512m join_buffer_size=128m sort_buffer_size=32m bulk_insert_buffer_size = 64m ###file size max_binlog_size = 50m innodb_log_file_size=128m ###replication server-id=1 log_bin=on binlog_expire_logs_seconds = 2592000 binlog_format=row gtid_mode=on enforce_gtid_consistency=on log-slave-updates=1 skip_slave_start=0 enforce_gtid_consistency=on master_info_repository=table relay_log_info_repository=table binlog_checksum=none log_bin=/data/mysql/mysqldata/mysql3306/binlog/mysql-bin log_bin_index=/data/mysql/mysqldata/mysql3306/binlog/mysql-bin.index relay-log-index = /data/mysql/mysqldata/mysql3306/relaylog/mysql-relay-bin.index relay-log = /data/mysql/mysqldata/mysql3306/relaylog/mysql-relay-bin
修改用户权限
useradd mysql chown -r mysql:mysql /data/mysql/mysqldata/ chown -r mysql:mysql /data/mysql/mysqlbase/ chmod 755 /data/mysql/mysqlbase/ chmod 755 /data/mysql/mysqldata/
启动数据库
/data/mysql/mysqlbase/mysql3306/bin/mysqld --defaults-file=/data/mysql/mysqldata/mysql3306/my8.cnf --datadir=/data/mysql/mysqldata/mysql3306/data --user=mysql --initialize-insecure --console /data/mysql/mysqlbase/mysql3306/bin/mysqld_safe --defaults-file=/data/mysql/mysqldata/mysql3306/my8.cnf 2>&1 &
登录数据库修改密码
/data/mysql/mysqlbase/mysql3306/bin/mysql -s /data/mysql/mysqldata/mysql3306/sock/mysql.sock -a set sql_log_bin=0; alter user 'root'@'localhost' identified by 'root'; update mysql.user set host='%' where user='root'; flush privileges; set sql_log_bin=1; exit; /data/mysql/mysqlbase/mysql3306/bin/mysql -uroot -proot -s /data/mysql/mysqldata/mysql3306/sock/mysql.sock -a
mgr配置
创建mgr用户(三个)
set sql_log_bin=0; create user mgruser@'%' identified by 'mgruser'; grant replication slave on *.* to mgruser@'%'; #mysql8.0默认认证插件为 caching_sha2_password,需要ssl,在启动mgr的时候没有ssl会报错,修改为mysql_native_password 避免 alter user 'mgruser'@'%' identified with mysql_native_password by 'mgruser'; flush privileges; set sql_log_bin=1; change master to master_user='mgruser', master_password='mgruser' for channel 'group_replication_recovery';
安装mgr插件(三个)
install plugin group_replication soname 'group_replication.so'; show plugins;
添加配置文件
主节点
vim /data/mysql/mysqldata/mysql3306/my8.cnf #修改server_id,每个节点必须不一样 server-id=1 ###mgr # 8.0 默认值xxhash64,针对写事务进行哈希处理 transaction_write_set_extraction=xxhash64 # 启动加载组复制插件 #plugin_load_add='group_replication.so' # 集群唯一id group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" # 是否启动mysql服务时启动组复制,建议值:off group_replication_start_on_boot=off # 本地ip后面端口33061可自定义,集群通信端口,建议统一端口 group_replication_local_address= "192.168.160.205:33061" # 初始化集群成员列表,可动态修改 group_replication_group_seeds= "192.168.160.205:33061,192.168.160.203:33061,192.168.160.206:33061" # 判断是否为引导组 group_replication_bootstrap_group=off group_replication_single_primary_mode = on # 单主模式(默认,可选多主模式 off) # 设置白名单,这里特别注意,如果是同网段可以不用设置,如果是不同网段则需要修改否则通信端口不可访问 loose-group_replication_ip_whitelist='192.168.160.205,192.168.160.203,192.168.160.206'
节点2
vim /data/mysql/mysqldata/mysql3306/my8.cnf #修改server_id,每个节点必须不一样 server-id=2 ###mgr # 8.0 默认值xxhash64,针对写事务进行哈希处理 transaction_write_set_extraction=xxhash64 # 启动加载组复制插件 #plugin_load_add='group_replication.so' # 集群唯一id group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" # 是否启动mysql服务时启动组复制,建议值:off group_replication_start_on_boot=off # 本地ip后面端口33061可自定义,集群通信端口,建议统一端口 group_replication_local_address= "192.168.160.203:33061" # 初始化集群成员列表,可动态修改 group_replication_group_seeds= "192.168.160.205:33061,192.168.160.203:33061,192.168.160.206:33061" # 判断是否为引导组 group_replication_bootstrap_group=off group_replication_single_primary_mode = on # 单主模式(默认,可选多主模式 off) # 设置白名单,这里特别注意,如果是同网段可以不用设置,如果是不同网段则需要修改否则通信端口不可访问 loose-group_replication_ip_whitelist='192.168.160.205,192.168.160.203,192.168.160.206'
节点3
vim /data/mysql/mysqldata/mysql3306/my8.cnf #修改server_id,每个节点必须不一样 server-id=3 ###mgr # 8.0 默认值xxhash64,针对写事务进行哈希处理 transaction_write_set_extraction=xxhash64 # 启动加载组复制插件 #plugin_load_add='group_replication.so' # 集群唯一id group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" # 是否启动mysql服务时启动组复制,建议值:off group_replication_start_on_boot=off # 本地ip后面端口33061可自定义,集群通信端口,建议统一端口 group_replication_local_address= "192.168.160.206:33061" # 初始化集群成员列表,可动态修改 group_replication_group_seeds= "192.168.160.205:33061,192.168.160.203:33061,192.168.160.206:33061" # 判断是否为引导组 group_replication_bootstrap_group=off group_replication_single_primary_mode = on # 单主模式(默认,可选多主模式 off) # 设置白名单,这里特别注意,如果是同网段可以不用设置,如果是不同网段则需要修改否则通信端口不可访问 loose-group_replication_ip_whitelist='192.168.160.205,192.168.160.203,192.168.160.206'
重启mysql服务(三个)
shutdown; exit; /data/mysql/mysqlbase/mysql3306/bin/mysqld_safe --defaults-file=/data/mysql/mysqldata/mysql3306/my8.cnf 2>&1 & /data/mysql/mysqlbase/mysql3306/bin/mysql -uroot -proot -s /data/mysql/mysqldata/mysql3306/sock/mysql.sock -a
主库启动mgr
set global group_replication_bootstrap_group=on; start group_replication; set global group_replication_bootstrap_group=off;
从库加入mgr
start group_replication;
查看成员状态
select * from performance_schema.replication_group_members;

mgr常用命令
-- 启动mgr(节点加入集群)
start group_replication;
-- 停止mgr(节点退出集群)
stop group_replication;
---------------------------------------------------------------------------------
-- 查看所有节点的id、主机、端口、状态(online/recovering/offline等)
select * from performance_schema.replication_group_members;
-------------------------------------------------------------------------------
-- 区分主节点(primary)和从节点(secondary)
select member_id, member_host, member_role from performance_schema.replication_group_members;
-----------------------------------------------------------------------------
-- 对比所有节点已执行的gtid集合,确认数据是否一致
select member_id,member_host,@@global.gtid_executed as executed_gtid
from performance_schema.replication_group_members;
-----------------------------------------------------------------------------
-- 查看节点发送/接收字节数、事务数等
select * from performance_schema.replication_group_member_stats;
----------------------------------------------------------------------------
--加入新节点,在新节点执行以下命令
-- 1. 配置集群通信用户(与集群其他节点一致)
change replication source to
source_user = 'mgr_repl', -- 复制用户名
source_password = 'repl_pass' -- 密码
for channel 'group_replication_recovery';
-- 2. 启动mgr加入集群
start group_replication;
---------------------------------------------------------------------------
--单主模式下切换主节点(集群必须要是正常的)
-- 语法:select group_replication_set_as_primary('目标节点的member_id');
-- 示例:将member_id为'1234-...'的节点设为主节点
select group_replication_set_as_primary('12345678-aaaa-bbbb-cccc-1234567890ab');
--------------------------------------------------------------------------
--切换集群模式
-- 1. 所有节点停止mgr
stop group_replication;
-- 2. 切换为多主模式(所有节点执行)
set global group_replication_single_primary_mode = off;
-- 或切换为单主模式
set global group_replication_single_primary_mode = on;
-- 3. 所有节点重启mgr生效
start group_replication;
--------------------------------------------------------------------------
-- 查看group_replication_recovery通道的连接状态(节点加入时的数据同步)
select * from performance_schema.replication_connection_status
where channel_name = 'group_replication_recovery';
-------------------------------------------------------------------------
--重置节点复制配置信息
-- 停止mgr
stop group_replication;
-- 重置recovery通道的复制配置
reset slave all for channel 'group_replication_recovery';
-- 重新配置复制用户(若需)
change replication source to
source_user = 'mgr_repl',
source_password = 'repl_pass'
for channel 'group_replication_recovery';
-- 重启mgr
start group_replication;
---------------------------------------------------------------------------到此这篇关于mysql mgr搭建的实现步骤的文章就介绍到这了,更多相关mysql mgr搭建内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论