MGR是MySQL Group Replication的缩写,即MySQL组复制。
在以往,我们一般是利用MySQL的主从复制或半同步复制来提供高可用解决方案,但这存在以下几个比较严重的问题:
-
主从复制间容易发生复制延迟,尤其是在5.6以前的版本,以及当数据库实例中存在没有显式主键表时,很容易发生。
-
主从复制节点间的数据一致性无法自行实现最终一致性。
-
当主节点发生故障时,如果有多个从节点,无法自动从中选择合适的节点作为新的主节点。
-
如果采用(增强)半同步复制,那么当有个从节点因为负载较高、网络延迟或其他意外因素使得事务无法及时确认时,也会反过来影响主节点的事务提交。
MGR具备以下几个特点:
-
基于shared-nothing模式,所有节点都有一份完整数据,发生故障时可以直接切换。
-
MGR提供了数据一致性保障,默认是最终一致性,可根据业务特征需要自行调整一致性级别。
-
支持在线添加、删除节点,节点管理更方便。
-
支持故障自动检测及自动切换,发生故障时能自动切换到新的主节点,再配合MySQL Router中间件,应用层无需干预或调整。
-
支持单节点、多节点写入两种模式,可根据架构或业务需要选择哪种方案,不过强烈建议选用单主模式。
安装MGR集群
系统为Rocky 8.10三台,IP地址分别为192.168.40.13{4..6}
cat >> /etc/hosts << EOF
192.168.40.134 134host
192.168.40.135 135host
192.168.40.136 136host
EOF
安装MySQL8
yum install mysql-server -y &> /dev/null
配置&启动
配置文件为vim /etc/my.cnf.d/mysql-server.cnf
配置内容和相关信息:(注:uuid可以在终端使用uuidgen直接生成然后复制过来即可)
#/etc/my.cnf*.d/mysql-server.cnf
[mysqld]
...
#开启GTID,必须开启
gtid_mode = ON
#强制GTID的一致性
enforce_gtid_consistency = ON
#binlog格式,MGR要求必须是ROW,不过就算不是MGR,也最好用
binlog_format = row
#server-id必须是唯一的
server-id = 133
#MGR使用乐观锁,所以官网建议隔离级别是RC,减少锁粒度
transaction_isolation = READ-COMMITTED
#因为集群会在故障恢复时互相检查binlog的数据,
#所以需要记录下集群内其他服务器发过来已经执行过的binlog,按GTID来区分是否执行过.
log-slave-updates = 1
#binlog校验规则,5.6之后的高版本是CRC32,低版本都是NONE,但是MGR要求使用NONE
binlog_checksum = NONE
#基于安全的考虑,MGR集群要求复制模式要改成slave记录记录到表中,不然就报错
master_info_repository = TABLE
#同上配套
relay_log_info_repository = TABLE
#组复制设置#记录事务的算法,官网建议设置该参数使用 XXHASH64 算法
transaction_write_set_extraction = XXHASH64
#相当于此GROUP的名字,是UUID值,不能和集群内其他GTID值的UUID混用,可用uuidgen来生成一个新的,
#主要是用来区分整个内网里边的各个不同的GROUP,而且也是这个group内的GTID值的UUID
loose-group_replication_group_name = '5dbabbe6-8050-49a0-9131-1de449167446'
#IP地址白名单,默认只添加127.0.0.1,不会允许来自外部主机的连接,按需安全设置
loose-group_replication_ip_whitelist = '127.0.0.1/8,192.168.40.0/24'
#是否随服务器启动而自动启动组复制,不建议直接启动,怕故障恢复时有扰乱数据准确性的特殊情况
loose-group_replication_start_on_boot = OFF
#本地MGR的IP地址和端口,host:port,是MGR的端口,不是数据库的端口
loose-group_replication_local_address = '192.168.40.150:33081'
#需要接受本MGR实例控制的服务器IP地址和端口,是MGR的端口,不是数据库的端口
loose-group_replication_group_seeds = '192.168.40.150:33081,192.168.40.133:33081,192.168.40.152:33081'
#开启引导模式,添加组成员,用于第一次搭建MGR或重建MGR的时候使用,只需要在集群内的其中一台开启,
loose-group_replication_bootstrap_group = OFF
#是否启动单主模式,如果启动,则本实例是主库,提供读写,其他实例仅提供读,如果为off就是多主模式了
loose-group_replication_single_primary_mode = ON
#多主模式下,强制检查每一个实例是否允许该操作,如果不是多主,可以关闭
#loose-group_replication_enforce_update_everywhere_checks = on
上面的配置在每个节点进行同样的配置,只需修改IP和server-id
然后查看密码:grep -i password /var/log/mysql/mysqld.log,发现里面是没有密码的
[root@localhost ~]# grep -i password /var/log/mysql/mysqld.log
2025-02-11T08:53:38.546214Z 6 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
那我们直接登录,登录之后需要下载插件,使用命令:(终端)
mysql -e "install plugin group_replication soname 'group_replication.so'"
[root@localhost ~]# mysql -e "show plugins;" | grep "group_replication"
group_replication ACTIVE GROUP REPLICATION group_replication.so GPL
以上就说明插件安装好了
接下来创建MGR服务专用账户,并准备配置MGR服务通道,明文创建用户的时候这个操作没必要记录binlog,每个mysql主机上面创建用户是为了后面可以开启多主模式
mysql> set session sql_log_bin=0;
mysql> create user 'test'@'%' identified with mysql_native_password by '@OPENlab123';
mysql> GRANT BACKUP_ADMIN, REPLICATION SLAVE ON *.* TO 'test'@'%';
#创建完用户后继续启用binlog记录
mysql> set session sql_log_bin=1;
#配置MGR服务通道
#通道名字 group_replication_recovery 是固定的,不能修改
mysql> CHANGE MASTER TO MASTER_USER='test', MASTER_PASSWORD='@OPENlab123' FOR CHANNEL 'group_replication_recovery';
上面要在所有节点上面进行操作,接下来进入mysql配置
-
当你首次启动Group Replication集群时,需要一个节点来初始化整个集群。这个节点被称为“引导节点”。
-
group_replication_bootstrap_group=ON
表示当前节点将作为引导节点,初始化一个新的集群。 -
如果不设置为
ON
,节点会尝试加入一个已经存在的集群,而此时集群尚未初始化,因此会报错。
所以启动命令为下:(后面设置为OFF,这一步是必要的,以确保后续加入的节点不会尝试初始化新的集群)
SET GLOBAL group_replication_bootstrap_group = ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group = OFF;
在mgr2\mgr3节点,进入mysql服务端,不需要SET GLOBAL group_replication_bootstrap_group = ON;
START GROUP_REPLICATION;
然后使用命令查看状态:SELECT * FROM performance_schema.replication_group_members;
如果出现MEMBER_STATE都为ONLINE则表示成功启动,如果出现了RECOVERING字段,那么查看日志tail /var/log/mysql/mysqld.log,一般都是/etc/hosts文件配置问题,里面的主机名要和系统主机名一致
上图可知我的136host为primary其他为secondary,下面我们进行转为多主模式和切换单主主机
切换主节点
我们通过上图中的MEMBER_ID可以看到每台主机是不同的,我们使用命令进行切换:
这里切换为135host为主节点
select group_replication_set_as_primary('1db22c88-e8ee-11ef-b7ab-000c299b2989');
这条命令可以在任何主机上执行,里面的那串数字就是MEMBER_ID,primary变为了135host
切换多主模式
在任何主机上面执行命令:select group_replication_switch_to_multi_primary_mode();
切换回单主模式
在任何主机上面执行命令:select group_replication_switch_to_single_primary_mode();
添加新节点和删除节点
新增
首先,要先完成MySQL Server初始化,创建好MGR专用账户、设置好MGR服务通道等前置工作。步骤同上
接下来,直接执行命令 start group_replication
启动MGR服务即可,新增的节点会进入分布式恢复这个步骤,它会从已有节点中自动选择一个作为捐献者(donor),并自行决定是直接读取binlog进行恢复,还是利用Clone进行全量恢复。
为了降低对primary节点的影响,建议选择其他的Secondary节点
新增节点:IP 192.168.40.137 137host
mysql> set global clone_valid_donor_list='192.168.150.136:3306';
在这个节点先停掉mgr服务(如果你之前启用了的话),关闭super_read_only模式
stop group_replication;
set global super_read_only=0;
clone instance from 'test'@192.168.40.136:3306 identified by '@OPENlab123';
上面填写的端口值3306不是mgr服务的端口,全量复制完数据后,该节点会进行一次自动重启。之后执行start group_replication,就可以正常加入集群了。
删除
在命令行模式下,一个节点想退出MGR集群,直接执行 stop group_replication
即可,如果这个节点只是临时退出集群,后面还想加回集群,则执行 start group_replication
即可自动再加入。而如果是想彻底退出集群,则停止MGR服务后,执行 reset master; reset slave all;
重置所有复制(包含MGR)相关的信息就可以了。
重启MGR集群
正常情况下,MGR集群中的Primary节点退出时,剩下的节点会自动选出新的Primary节点。当最后一个节点也退出时,相当于整个MGR集群都关闭了。这时候任何一个节点启动MGR服务后,都不会自动成为Primary节点,需要在启动MGR服务前,先设置 group_replication_bootstrap_group=ON
,使其成为引导节点,再启动MGR服务,它才会成为Primary节点,后续启动的其他节点也才能正常加入集群。可自行测试,这里不再做演示。参考上面的引导节点启动(启动完毕之后要group_replication_bootstrap_group=OFF关闭
)
小结:
MGR和传统主从复制类似,在运行过程中主要关注各节点的运行状态,以及Secondary节点的事务是否有延迟。本文介绍如何监控MGR节点状态、事务状态等。
-
表示各节点的状态,共有几种状态:ONLINE、RECOVERING、OFFLINE、ERROR、UNREACHABLE 等,下面分别介绍几种状态。
-
ONLINE,表示节点处于正常状态,可提供服务。
-
RECOVERING,表示节点正在进行分布式恢复,等待加入集群,这时候有可能正在从donor节点利用clone复制数据,或者传输binlog中。
-
OFFLINE,表示该节点当前处于离线状态。提醒,在正要加入或重加入集群时,可能也会有很短瞬间的状态显示为 OFFLINE。
-
ERROR,表示该节点当前处于错误状态,无法成为集群的一员。当节点正在进行分布式恢复或应用事务时,也是有可能处于这个状态的。当节点处于ERROR状态时,是无法参与集群事务裁决的。节点正在加入或重加入集群时,在完成兼容性检查成为正式MGR节点前,可能也会显示为ERROR状态。
-
UNREACHABLE,当组通信消息收发超时时,故障检测机制会将本节点标记为怀疑状态,怀疑其可能无法和其他节点连接,例如当某个节点意外断开连接时。当在某个节点上看到其他节点处于 UNREACHABLE 状态时,有可能意味着此时部分节点发生了网络分区,也就是多个节点分裂成两个或多个子集,子集内的节点可以互通,但子集间无法互通。
-
利用MySQL Router构建读写分离MGR集群
这里注重介绍利用MYSQL Router实现读写分离,读负载均衡和故障自动转移
建议把MySQL Router部署在应用服务器上,每个应用服务器都部署一套,这样应用程序可以直接连接本机IP,连接的效率更高,而且后端数据库发生变化时,程序端也无需修改IP配置。
部署MySQL Router
安装包去官网上面找对应和自己MySQL版本相同的安装(建议),安装选择mysql-router版本的
安装:rpm -ivh mysql-router-community-8.0.36-1.el8.x86_64.rpm
安装之后直接启动即可:systemctl enable --now mysqlrouter.service(开机自启)
[root@135host ~]# ps -ef | grep -v grep | grep mysqlrouter
mysqlro+ 27361 1 0 12:23 ? 00:00:00 /usr/bin/mysqlrouter
上面可以看到已经是正常启动了(本人资源有限,就在安装的有MGR上的主机上将就安装)
mysqlrouter的初始化自动生成的配置文件是:/etc/mysqlrouter/mysqlrouter.conf
写入以下内容
cat >> /etc/mysqlrouter/mysqlrouter.conf << EOF
[routing:write]
bind_address = 192.168.40.135#本地的IP地址
bind_port = 8001#自定义一个端口号用于监听读写
mode = read-write
destinations = 192.168.40.136:3306#目标MRG集群的primary主机
[routing:blanace]
bind_address = 192.168.40.135
bind_port = 8002#自定义一个端口用于监听读
mode = read-only
destinations = 192.168.40.135:3306,192.168.40.134:3306
EOF
[root@135host ~]systemctl restart mysqlrouter.service#重启
确认分离效果:(创建用户只能在primary节点上面创建)
mysql> create user 'admin'@'%' identified with mysql_native_password by '@OPENlab123';
Query OK, 0 rows affected (0.09 sec)
mysql> grant all on *.* to admin@'%';
Query OK, 0 rows affected (0.02 sec)
我们先使用命令在mysql终端中:
mysql> select MEMBER_ID,MEMBER_ROLE from performance_schema.replication_group_members;
+--------------------------------------+-------------+
| MEMBER_ID | MEMBER_ROLE |
+--------------------------------------+-------------+
| 165f4dc6-e8ee-11ef-bd10-000c29481d69 | PRIMARY |
| 1db22c88-e8ee-11ef-b7ab-000c299b2989 | SECONDARY |
| a9389006-e8ed-11ef-a2f2-000c29017dd6 | SECONDARY |
+--------------------------------------+-------------+
3 rows in set (0.00 sec)
然后在可以远程登录安装的有MySQL Router的主机:如果登录的MEMBER_ID为PEIMARY的话则表明,写分离成功
mysql -uadmin -p@OPENlab123 -h192.168.40.135 -P8001
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 53
Server version: 8.0.36 Source distribution
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> select @@server_uuid;
+--------------------------------------+
| @@server_uuid |
+--------------------------------------+
| 165f4dc6-e8ee-11ef-bd10-000c29481d69 |
+--------------------------------------+
1 row in set (0.01 sec)
经验证连接到了PRIMARY节点上,而换8002端口,开两个线程连接的话,一个会到134,一个会到135
mysql> select @@server_uuid;
+--------------------------------------+
| @@server_uuid |
+--------------------------------------+
| 1db22c88-e8ee-11ef-b7ab-000c299b2989 |
+--------------------------------------+
1 row in set (0.00 sec)
mysql> select @@server_uuid;
+--------------------------------------+
| @@server_uuid |
+--------------------------------------+
| a9389006-e8ed-11ef-a2f2-000c29017dd6 |
+--------------------------------------+
1 row in set (0.01 sec)
总结:
本文介绍了如何利用MySQL Router实现读写分离、读负载均衡,以及故障自动转移,利用MySQL Router可以提升应用端的透明性,后端数据库发生一些变化时,应用端无需跟着频繁变更。