作者公众号,欢迎一起交流。
1 背景
MySQL Group Replication(简称MGR)是MySQL官方于2016年12月12日推出的一款高可用与高扩展的解决方案,它提供了高可用、高扩展、高可靠的MySQL集群服务,具有以下特点:
- 强一致性:基于原生复制和paxos协议,保证数据传输的一致性和原子性
- 高容错性:只要大多数节点没有出现故障,集群就可对外提供服务
- 高扩展性:节点的加入和移除都是自动的,不需要人为过多干预
- 高灵活性:具有单主模式和多主模式,单主模式在主宕机后自动选主,多主模式多节点写入
2 组复制插件架构
MySQL MGR是一个MySQL插件,构建在现有MySQL复制基础架构上。MGR插件包括一组用于Capture、Apply和Lifecycle的API,用于控制插件如何与MySQL服务器进行交互。通过接口可以让信息在服务器和插件之间流转,而且这些接口将MySQL服务器核心从组复制插件隔离出来。从服务器到插件这个方向,会有如服务器启动、服务器恢复、服务器准备接受连接和服务器即将提交事务的事件的通知,而在另一个方向,即插件到服务器这个方向,插件指示服务器执行如提交或终止正在进行的事务,或在Relaylog中对事务排队这样的操作。
再往下一层是一组组件,包括Capture、Applier和Recovery,当通知路由到这些组件时会做出相应的响应。其中,Capture组件负责追踪正在执行事务的上下文信息,Applier组件负责在数据库上执行远程事务,Recover组件管理分布式恢复。
继续往下看,复制协议模块包含复制协议的特定逻辑,它处理冲突检测,接收事务并将其传播到组。
最后两层是组通信系统(GCS)API,以及基于Paxos的组通信引擎的实现。
3 配置要求和限制
组复制的使用需要满足如下要求:
- InnoDB存储引擎
- 每个表必须有显式主键
- 网络性能要求低延时、高带宽
- server_id要唯一
- 开启GTID
- 事务隔离级别建议使用RC
- 不建议使用外键级联约束
- 组成员最大数目为9
4 单主模式部署
4.1 部署环境
Hostname | IP | Server ID | Port |
node1 | 192.168.56.201 | 201 | 3306 |
node2 | 192.168.56.202 | 202 | 3306 |
node3 | 192.168.56.203 | 203 | 3306 |
4.2 安装部署
4.2.1 安装MySQL数据库软件
1)分别在节点node1、node2和node3的/etc/hosts文件增加如下配置:
192.168.56.201 node1 node1.com.cn
192.168.56.202 node2 node2.com.cn
192.168.56.203 node3 node3.com.cn
2)分别在节点node1、node2和node3关闭防火墙:
查看防火墙状态:
systemctl status firewalld
关闭防火墙:
systemctl stop firewalld
禁用防火墙启动:
systemctl disable firewalld
3)安装MySQL数据库,参照【MySQL 8.0 数据库安装部署】分别在节点node1、node2和node3安装MySQL数据库软件。
4.2.2 安装主节点node1
1)配置组复制,在原有的配置文件/etc/my.cnf中增加如下配置信息:
disabled_storage_engines = "MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_checksum = CRC32
plugin_load_add = 'group_replication.so'
group_replication_group_name = "0b15d45f-6e29-11ec-99b3-08002790c7d5"
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
2)重启MySQL服务器实例使配置生效:
[root@node1 ~]# service mysql.server restart
Shutting down MySQL.... SUCCESS!
Starting MySQL....... SUCCESS!
3)连接MySQL服务器创建分布式恢复用户并授予权限,若使用Clone操作,需授予对应的权限:
mysql> set sql_log_bin=0;
Query OK, 0 rows affected (0.00 sec)
mysql> create user repl identified by 'repl';
Query OK, 0 rows affected (0.12 sec)
mysql> grant replication slave on *.* to repl;
Query OK, 0 rows affected (0.11 sec)
mysql> grant backup_admin on *.* to repl;
Query OK, 0 rows affected (0.10 sec)
mysql> set sql_log_bin=1;
Query OK, 0 rows affected (0.00 sec)
mysql> change replication source to source_user='repl',source_password='repl' for channel 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.17 sec)
4)引导组,第一次启动组时需使用group_replication_bootstrap_group系统变量引导组,该操作只能在单个服务器完成,并且只能启动一次,引导完成查看组成员信息:
mysql> set global group_replication_bootstrap_group=on;
Query OK, 0 rows affected (0.00 sec)
mysql> start group_replication;
Query OK, 0 rows affected (1.29 sec)
mysql> set global group_replication_bootstrap_group=off;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from performance_schema.replication_group_members\G;
*************************** 1. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: a6886158-6ef5-11ec-a75e-08002790c7d5
MEMBER_HOST: node1.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
1 row in set (0.12 sec)
ERROR:
No query specified
5)出于演示目的,创建测试表:
mysql> create database test;
Query OK, 1 row affected (0.18 sec)
mysql> use test;
Database changed
mysql> create table t1(id int primary key,name varchar(20));
Query OK, 0 rows affected (0.21 sec)
mysql> insert into t1 values(1,'Alen');
Query OK, 1 row affected (0.03 sec)
mysql> show binary logs;
+------------------+-----------+-----------+
| Log_name | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000001 | 179 | No |
| mysql-bin.000002 | 500 | No |
| mysql-bin.000003 | 1190 | No |
+------------------+-----------+-----------+
3 rows in set (0.00 sec)
mysql> show binlog events in 'mysql-bin.000003';
+------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------------------+
| mysql-bin.000003 | 4 | Format_desc | 201 | 125 | Server ver: 8.0.27, Binlog ver: 4 |
| mysql-bin.000003 | 125 | Previous_gtids | 201 | 156 | |
| mysql-bin.000003 | 156 | Gtid | 201 | 242 | SET @@SESSION.GTID_NEXT= '0b15d45f-6e29-11ec-99b3-08002790c7d5:1' |
| mysql-bin.000003 | 242 | Query | 201 | 308 | BEGIN |
| mysql-bin.000003 | 308 | View_change | 201 | 411 | view_id=16414770057187861:1 |
| mysql-bin.000003 | 411 | Query | 201 | 483 | COMMIT |
| mysql-bin.000003 | 483 | Gtid | 201 | 567 | SET @@SESSION.GTID_NEXT= '0b15d45f-6e29-11ec-99b3-08002790c7d5:2' |
| mysql-bin.000003 | 567 | Query | 201 | 675 | create database test /* xid=25 */ |
| mysql-bin.000003 | 675 | Gtid | 201 | 759 | SET @@SESSION.GTID_NEXT= '0b15d45f-6e29-11ec-99b3-08002790c7d5:3' |
| mysql-bin.000003 | 759 | Query | 201 | 899 | use `test`; create table t1(id int primary key,name varchar(20)) /* xid=30 */ |
| mysql-bin.000003 | 899 | Gtid | 201 | 985 | SET @@SESSION.GTID_NEXT= '0b15d45f-6e29-11ec-99b3-08002790c7d5:4' |
| mysql-bin.000003 | 985 | Query | 201 | 1060 | BEGIN |
| mysql-bin.000003 | 1060 | Table_map | 201 | 1114 | table_id: 93 (test.t1) |
| mysql-bin.000003 | 1114 | Write_rows | 201 | 1159 | table_id: 93 flags: STMT_END_F |
| mysql-bin.000003 | 1159 | Xid | 201 | 1190 | COMMIT /* xid=31 */ |
+------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------------------+
15 rows in set (0.00 sec)
4.2.3 新增从节点node2
新增从节点node2的操作和node1相似,可参照node1的配置过程,只不过不再需要引导组了。
1)配置组复制,在原有节点node2的配置文件/etc/my.cnf中增加如下配置信息,需修改server_id等配置选项:
server_id = 202
disabled_storage_engines = "MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_checksum = CRC32
plugin_load_add = 'group_replication.so'
group_replication_group_name = "0b15d45f-6e29-11ec-99b3-08002790c7d5"
group_replication_start_on_boot = off
group_replication_local_address = "node2:33061"
group_replication_group_seeds = "node1:33061,node2:33061,node3:33061"
group_replication_bootstrap_group = off
2)重启MySQL服务器实例使配置生效:
[root@node2 ~]# service mysql.server restart
Shutting down MySQL.. SUCCESS!
Starting MySQL...... SUCCESS!
3)连接MySQL服务器创建分布式恢复用户并授予权限,若使用Clone操作,需授予对应的权限:
mysql> set sql_log_bin=0;
Query OK, 0 rows affected (0.00 sec)
mysql> create user repl identified by 'repl';
Query OK, 0 rows affected (0.06 sec)
mysql> grant replication slave on *.* to repl;
Query OK, 0 rows affected (0.01 sec)
mysql> grant backup_admin on *.* to repl;
Query OK, 0 rows affected (0.11 sec)
mysql> set sql_log_bin=1;
Query OK, 0 rows affected (0.00 sec)
mysql> change replication source to source_user='repl',source_password='repl'\
-> for channel 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.19 sec)
4)启动组复制并查看成员状态:
mysql> start group_replication;
Query OK, 0 rows affected (6.95 sec)
mysql> select * from performance_schema.replication_group_members\G;
*************************** 1. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: 4bfafef9-6efa-11ec-8296-080027e8893b
MEMBER_HOST: node2.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
*************************** 2. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: a6886158-6ef5-11ec-a75e-08002790c7d5
MEMBER_HOST: node1.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
2 rows in set (0.16 sec)
ERROR:
No query specified
5)验证从node1节点同步过来的数据:
mysql> select * from test.t1;
+----+------+
| id | name |
+----+------+
| 1 | Alen |
+----+------+
1 row in set (0.00 sec)
mysql> show binlog events in 'mysql-bin.000003';
+------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------------------+
| mysql-bin.000003 | 4 | Format_desc | 202 | 125 | Server ver: 8.0.27, Binlog ver: 4 |
| mysql-bin.000003 | 125 | Previous_gtids | 202 | 156 | |
| mysql-bin.000003 | 156 | Gtid | 201 | 242 | SET @@SESSION.GTID_NEXT= '0b15d45f-6e29-11ec-99b3-08002790c7d5:1' |
| mysql-bin.000003 | 242 | Query | 201 | 308 | BEGIN |
| mysql-bin.000003 | 308 | View_change | 201 | 415 | view_id=16414770057187861:1 |
| mysql-bin.000003 | 415 | Query | 201 | 487 | COMMIT |
| mysql-bin.000003 | 487 | Gtid | 201 | 571 | SET @@SESSION.GTID_NEXT= '0b15d45f-6e29-11ec-99b3-08002790c7d5:2' |
| mysql-bin.000003 | 571 | Query | 201 | 679 | create database test /* xid=31 */ |
| mysql-bin.000003 | 679 | Gtid | 201 | 763 | SET @@SESSION.GTID_NEXT= '0b15d45f-6e29-11ec-99b3-08002790c7d5:3' |
| mysql-bin.000003 | 763 | Query | 201 | 903 | use `test`; create table t1(id int primary key,name varchar(20)) /* xid=32 */ |
| mysql-bin.000003 | 903 | Gtid | 201 | 989 | SET @@SESSION.GTID_NEXT= '0b15d45f-6e29-11ec-99b3-08002790c7d5:4' |
| mysql-bin.000003 | 989 | Query | 201 | 1059 | BEGIN |
| mysql-bin.000003 | 1059 | Table_map | 201 | 1113 | table_id: 90 (test.t1) |
| mysql-bin.000003 | 1113 | Write_rows | 201 | 1158 | table_id: 90 flags: STMT_END_F |
| mysql-bin.000003 | 1158 | Xid | 201 | 1189 | COMMIT /* xid=34 */ |
| mysql-bin.000003 | 1189 | Gtid | 201 | 1275 | SET @@SESSION.GTID_NEXT= '0b15d45f-6e29-11ec-99b3-08002790c7d5:5' |
| mysql-bin.000003 | 1275 | Query | 201 | 1341 | BEGIN |
| mysql-bin.000003 | 1341 | View_change | 201 | 1554 | view_id=16414770057187861:2 |
| mysql-bin.000003 | 1554 | Query | 201 | 1626 | COMMIT |
| mysql-bin.000003 | 1626 | Gtid | 201 | 1712 | SET @@SESSION.GTID_NEXT= '0b15d45f-6e29-11ec-99b3-08002790c7d5:6' |
| mysql-bin.000003 | 1712 | Query | 201 | 1778 | BEGIN |
| mysql-bin.000003 | 1778 | View_change | 201 | 1925 | view_id=16414770057187861:4 |
| mysql-bin.000003 | 1925 | Query | 201 | 1997 | COMMIT |
+------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------------------+
23 rows in set (0.00 sec)
4.2.4 新增从节点node3
1)新增从节点node3的操作可参考从节点node2的添加过程,仅仅是配置选项不同,其它操作过程一样,node3配置文件/etc/my.cnf配置选项如下:
server_id = 203
disabled_storage_engines = "MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_checksum = CRC32
plugin_load_add = 'group_replication.so'
group_replication_group_name = "0b15d45f-6e29-11ec-99b3-08002790c7d5"
group_replication_start_on_boot = off
group_replication_local_address = "node3:33061"
group_replication_group_seeds = "node1:33061,node2:33061,node3:33061"
group_replication_bootstrap_group = off
2)新增从节点node3完成后,查看组成员信息,都处于在线状态:
mysql> select * from performance_schema.replication_group_members\G;
*************************** 1. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: 07cad00b-6efd-11ec-87cc-08002715e2e8
MEMBER_HOST: node3.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
*************************** 2. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: 4bfafef9-6efa-11ec-8296-080027e8893b
MEMBER_HOST: node2.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
*************************** 3. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: a6886158-6ef5-11ec-a75e-08002790c7d5
MEMBER_HOST: node1.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
3 rows in set (0.01 sec)
ERROR:
No query specified
5 单主 / 多主模式切换
MySQL MGR默认运行在单主模式,即参数group_replication_single_primary_mode的值默认是ON,自MySQL 8.0.13开始,可以在MySQL MGR运行的情况下利用group_replication_switch_to_multi_primary_mode()和group_replication_switch_to_single_primary_mode()函数进行单主/多主的模式切换。
5.1 单主切换为多主
使用函数group_replication_switch_to_multi_primary_mode()可将单主模式切换为多主模式:
mysql> select group_replication_switch_to_multi_primary_mode();
+--------------------------------------------------+
| group_replication_switch_to_multi_primary_mode() |
+--------------------------------------------------+
| Mode switched to multi-primary successfully. |
+--------------------------------------------------+
1 row in set (1.00 sec)
mysql> select * from performance_schema.replication_group_members\G;
*************************** 1. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: 07cad00b-6efd-11ec-87cc-08002715e2e8
MEMBER_HOST: node3.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
*************************** 2. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: 4bfafef9-6efa-11ec-8296-080027e8893b
MEMBER_HOST: node2.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
*************************** 3. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: a6886158-6ef5-11ec-a75e-08002790c7d5
MEMBER_HOST: node1.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
3 rows in set (0.00 sec)
ERROR:
No query specified
5.2 多主切换为单主
使用函数group_replication_switch_to_single_primary_mode() 可将多主模式切换为单主模式:
mysql> select group_replication_switch_to_single_primary_mode();
+---------------------------------------------------+
| group_replication_switch_to_single_primary_mode() |
+---------------------------------------------------+
| Mode switched to single-primary successfully. |
+---------------------------------------------------+
1 row in set (0.03 sec)
mysql> select * from performance_schema.replication_group_members\G;
*************************** 1. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: 07cad00b-6efd-11ec-87cc-08002715e2e8
MEMBER_HOST: node3.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
*************************** 2. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: 4bfafef9-6efa-11ec-8296-080027e8893b
MEMBER_HOST: node2.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
*************************** 3. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: a6886158-6ef5-11ec-a75e-08002790c7d5
MEMBER_HOST: node1.com.cn
MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.27
MEMBER_COMMUNICATION_STACK: XCom
3 rows in set (0.00 sec)
ERROR:
No query specified
6 监视组复制环境
对于MySQL MGR的监视,主要是通过performance_schema下的表来实现,主要的表如下:
mysql> show tables from performance_schema like '%replication%';
+------------------------------------------------------+
| Tables_in_performance_schema (%replication%) |
+------------------------------------------------------+
| replication_applier_configuration |
| replication_applier_filters |
| replication_applier_global_filters |
| replication_applier_status |
| replication_applier_status_by_coordinator |
| replication_applier_status_by_worker |
| replication_asynchronous_connection_failover |
| replication_asynchronous_connection_failover_managed |
| replication_connection_configuration |
| replication_connection_status |
| replication_group_communication_information |
| replication_group_configuration_version |
| replication_group_member_actions |
| replication_group_member_stats |
| replication_group_members |
+------------------------------------------------------+
15 rows in set (0.01 sec)