MGR初探

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: MySQL Group Replication(MGR)是MySQL官方在5.7.17版本引进的一个数据库高可用与高扩展的解决方案,以插件形式提供。MGR基于分布式paxos协议,实现组复制,保证数据一致性。

一、MGR基础

1、复制背景
1.1 主从复制
传统MySQL提供了一种简单的主从复制方式,一个主,有一个或者多个从。主节点执行和提交事务,然后将他们发送到从节点,以重新执行(在基于语句的复制中)或者应用(在基于行的复制中)。这是一个 shared-nothing的系统,默认所有的server都有一个完整的数据副本。
test

MySQL异步复制


可以看到的是,异步复制是不考虑从库有没有接受binlog文件的,所以会造成主从不一致: 当主库commit一个事务后,数据库发生宕机,刚好它的binlog还没来得及传送到slave端,这个时候选任何一个slave端都会丢失这个事务,造成数据不一致情况。
所以还要一种半同步复制,它在协议中加了一个同步的步骤,这意味着主节点提交的时候需要等待从节点确认它已经收到了事物,只有这样主节点才能够继续提交。
test

MySQL半同步复制

从上面两个图中可以看到传统的MySQL复制协议。蓝色的箭头表示不同的server之间或者server和client应用之间的信息交互。

1.2 组复制
不管是异步复制还是半同步复制,都有两个弊端:

  • 写操作集中在MASTER服务器上;
  • MASTER宕机后,需要人为选择新主并重新给其他的slave端执行change master(可用第三方工具实现,但是mysql的复制就是没提供,所以也算是弊端)
    基于这种现状,MySQL官方提供了 MySQL Group Replication。

test

MySQL组复制

相对于传统的复制,MGR提供的功能有:
  • 多主:多写模式下支持集群中的所有节点都可以写入
  • 一致性: 依靠分布式一致性协议(Paxos协议的变体)确保集群中大部分节点收到日志
  • 弹性:同个MGR中,节点的加入或者移除都是自动调整
  • 可用性: 确保系统发生故障(包括脑裂)依然可用,双写对系统无影响

2、理论基础
MGR有单主和多主两种模式。
1.1 组复制
复制组由多个server成员组成,并且组中每个成员可以独立的执行事务。但是所有的读写(RW)事务只有在冲突检测成功后才会提交。只读事务(RO)不需要冲突检测,可以立即提交。
在始发server上,当事务准备好提交时,该server会广播写入值(已改变的行)和对应的写入集(已更新行的唯一标识符)。然后为该事物建立一个全局的顺序。最终,这意味着所有server成员以相同的顺序接收同一组事务。
因此,所有的server成员以相同的顺序应用相同的更改,以确保组内一致。
在不同的server上并发执行的事物可能存在冲突,根据组复制冲突检测机制。如果在不同server上执行的两个并发事务更新同一行,则存在冲突。冲突解决过程中,排在最前面的事物可以在所有server成员上提交,第二个事物在源server上回滚,并且在组中其他server上删除。其实这就是分布式的先提交当选原则。

1.2 容错
MySQL Group Replication构建于Paxos分布式算法的实现之上,以在服务器之间提供分布式协调。因此,它需要大多数服务器处于活动状态才能达到仲裁成员数,从而做出决定。这直接影响系统可以容忍的故障数量,以及自身及其整体功能。容忍f个故障所需的服务器数量 n= 2 x f + 1。
在实践中,这意味着为了容忍一个故障,该组必须具有三个server。因此,如果一个server发生故障,仍然有两个server构成多数(三分之二),并允许系统继续自动做出决策并继续进行。但是,如果第二个server以外fail掉 ,那么该组(剩下一个server)会锁定,因为没有多数人可以达成协议。
test

二、部署安装

1、单写部署
官方文档提供的是在一台服务器上安装3个mysql来搭建单主模式,这里是按照官方文档的步骤,但是部署在三台服务器上。
1.1 环境:
_
1.2 配置文件
编辑配置文件/data1/my3306.cnf,3个节点 除了server_id、loose-group_replication_local_address、report_host 三个参数不一样外,其他保持一致。

#GTID
server_id=11
gtid_mode=ON
#强制gtid一致性,开启后对于特定create table不被支持
#ON:不允许任何事务违反GTID一致性
enforce_gtid_consistency=ON

binlog_checksum=NONE
log_bin=binlog
log_slave_updates=ON
binlog_format=ROW
master_info_repository=TABLE
relay_log_info_repository=TABLE

#MGR
#定义用于生成标识与事务关联的写入的哈希的算法,哈希值将用于分布式冲突检测和处理
transaction_write_set_extraction=XXHASH64
#通知插件它正在加入或创建的组,可以使用SELECT UUID()生成一个UUID
loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
#指示插件在服务器启动时不自动引导组操作
loose-group_replication_start_on_boot=OFF
件使用哪个ip:port与组中的其他成员进行内部通信。这里的ip与端口不能与MySQL提供的ip:port 相同,如果使用相同ip则port必须不相同
loose-group_replication_local_address= "192.168.1.11:33061"
#设置组成员的主机名和端口
loose-group_replication_group_seeds= "192.168.1.11:33061,192.168.1.12:33061,192.168.1.13:33061"
#插件是否引导组,此选项只能在任何时候在一个服务器实例上使用,通常是第一次引导组时(或者在整个组关闭并重新备份的情况下)
loose-group_replication_bootstrap_group= off

1.3 安装启动
每个服务器是一个节点,都安装好mysql

mysqld --defaults-file=/data1/my3306.cnf --datadir=/data1/mysql3306 --user=mysql3306 --initialize-insecure
mysqld --defaults-file=/data1/my3308.cnf --datadir=/data1/mysql3308 --user=mysql3308 --initialize-insecure

启动:

/usr/local/mysql-5.7.26/bin/mysqld_safe --defaults-file=/data1/mysql3306/my3306.cnf &
/usr/local/mysql-5.7.26/bin/mysqld_safe --defaults-file=/data1/mysql3308/my3308.cnf &

1.4 安装MGR插件,设置复制账号(所有节点执行)

#无密码登录
#安装MGR插件
mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so';
#设置复制账号
mysql> SET SQL_LOG_BIN=0;
mysql> CREATE USER repl@'%' IDENTIFIED BY 'repl';
mysql> GRANT REPLICATION SLAVE ON *.* TO repl@'%';
mysql> FLUSH PRIVILEGES;
mysql> SET SQL_LOG_BIN=1;
mysql> CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='repl' FOR CHANNEL 'group_replication_recovery';

1.5 启动MGR单主模式

#主启动(任选一个作为主库,这里选择了1.11)
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;
mysql> SELECT * FROM performance_schema.replication_group_members;
#查看MGR组信息
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 463679cf-7222-11e9-9459-000c29a6154a | vm1         |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+

#其他节点加入MGR,在从库(1.12,1.13)上执行
mysql> START GROUP_REPLICATION;
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST  | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| group_replication_applier | 0bbd0bcc-7223-11e9-a4fc-000c296aa366 | 192.168.1.12 |        3308 | ONLINE       |
| group_replication_applier | 18f64c9b-7223-11e9-bba2-000c293610f1 | 192.168.1.13 |        3308 | ONLINE       |
| group_replication_applier | 463679cf-7222-11e9-9459-000c29a6154a | 192.168.1.11 |        3306 | ONLINE       |
+---------------------------+--------------------------------------+--------------+-------------+--------------+

#查找主节点:
mysql> SHOW STATUS LIKE 'group_replication_primary_member';
+----------------------------------+--------------------------------------+
| Variable_name                    | Value                                |
+----------------------------------+--------------------------------------+
| group_replication_primary_member | 463679cf-7222-11e9-9459-000c29a6154a |
+----------------------------------+--------------------------------------+
或者 
select variable_value from performance_schema.global_status where variable_name = 'group_replication_primary_member';

这个时候从是只读的,在上执行SQL会报错:

ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement

2、多写部署(单主切换到多主)
多主模式可以直接由单主模式切换, 需要在所有节点上先关闭组复制,设置 group_replication_single_primary_mode=OFF 等参数,再启动组复制。

# 停止组复制(所有节点执行):
mysql> stop group_replication;
#单主模式设置为ON,多主模式设置为OFF
mysql> set global group_replication_single_primary_mode=OFF;
#在所有节点启用多主数据更新的严格一致性检查
mysql> set global group_replication_enforce_update_everywhere_checks=ON;


# 随便选择某个节点执行(这里选择之前是从节点的1.12执行)
mysql> SET GLOBAL group_replication_bootstrap_group=ON;
mysql> START GROUP_REPLICATION;
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;

# 其他节点执行
mysql> START GROUP_REPLICATION;

mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST  | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| group_replication_applier | 0bbd0bcc-7223-11e9-a4fc-000c296aa366 | 192.168.1.12 |        3308 | ONLINE       |
| group_replication_applier | 18f64c9b-7223-11e9-bba2-000c293610f1 | 192.168.1.13 |        3308 | ONLINE       |
| group_replication_applier | 463679cf-7222-11e9-9459-000c29a6154a | 192.168.1.11 |        3306 | ONLINE       |
+---------------------------+--------------------------------------+--------------+-------------+--------------+

#多主模式,变量 group_replication_primary_member 为空(8.0版本会直接显示MEMBER_ROLE)
mysql> SHOW STATUS LIKE 'group_replication_primary_member';
+----------------------------------+-------+
| Variable_name                    | Value |
+----------------------------------+-------+
| group_replication_primary_member |       |
+----------------------------------+-------+
可以测试写入是多节点的

3、多主切换到单主模式

# 所有节点执行
mysql> stop group_replication;
mysql> set global group_replication_enforce_update_everywhere_checks=OFF;
mysql> set global group_replication_single_primary_mode=ON;


# 主节点(192.168.1.11)执行
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;
# 从节点(192.168.1.12、192.168.1.13)执行
START GROUP_REPLICATION;

三、节点加入

1.1 环境:(这里是在多主模式下加入,单主模式下亦然)
因为MGR也是使用的GTID,所以新节点的加入也是需要通过备份和binlog来进行恢复,然后加入组复制的。这里因为binlog都在,所以直接加入一个新安装的MySQL实例加入到组里。
_
1.2 新节点加入步骤

#新节点配置文件:
loose-group_replication_local_address= "192.168.1.14:33061"
loose-group_replication_group_seeds= "192.168.1.11:33061,192.168.1.12:33061,192.168.1.13:33061,192.168.1.14:33061"

#在其他三个节点执行:
set global group_replication_group_seeds='192.168.1.11:33061,192.168.1.12:33061,192.168.1.13:33061,192.168.1.14:33061';

#新节点加入:
set global group_replication_single_primary_mode=OFF;
set global group_replication_enforce_update_everywhere_checks=ON;
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='repl' FOR CHANNEL 'group_replication_recovery';

#查看所有节点:
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST  | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| group_replication_applier | 0bbd0bcc-7223-11e9-a4fc-000c296aa366 | 192.168.1.12 |        3308 | ONLINE       |
| group_replication_applier | 18f64c9b-7223-11e9-bba2-000c293610f1 | 192.168.1.13 |        3308 | ONLINE       |
| group_replication_applier | 241b7e73-74d4-11e9-aef0-000c293af32c | 192.168.1.14 |        3308 | ONLINE       |
| group_replication_applier | 463679cf-7222-11e9-9459-000c29a6154a | 192.168.1.11 |        3306 | ONLINE       |
+---------------------------+--------------------------------------+--------------+-------------+--------------+

到此新节点已经加入。

四、故障转移

1、多主模式
_
第三部分新加入了节点的时候属于多主模式,所以首先来看看,当多主模式下,有节点发生了故障会如何处理。
从图中很容易看出来,一个节点fail了,写线程直接连接到其他的节点上了,因为所有节点都是读写的,所以也就存在选取哪个为主节点了。
这里直接将1.12这个节点的MySQL给kill掉,看看对组的影响:

#kill了1.12之后,很明显这个节点直接被移出了
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST  | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| group_replication_applier | 18f64c9b-7223-11e9-bba2-000c293610f1 | 192.168.1.13 |        3308 | ONLINE       |
| group_replication_applier | 241b7e73-74d4-11e9-aef0-000c293af32c | 192.168.1.14 |        3308 | ONLINE       |
| group_replication_applier | 463679cf-7222-11e9-9459-000c29a6154a | 192.168.1.11 |        3306 | ONLINE       |
+---------------------------+--------------------------------------+--------------+-------------+--------------+

#给集群插入一些数据,再讲kill的节点重新加入组里
set global group_replication_single_primary_mode=OFF;
set global group_replication_enforce_update_everywhere_checks=ON;
START GROUP_REPLICATION;

可以发现新插入的数据同步到1.12节点了

2、单主模式
_
单主模式存在一个选取哪个为新主的过程,大体过程为:

通过安装字典顺序(使用其UUID)来排序剩余的server成员并选择列表中第一个成员来作为下一个 主节点。

先将多主模式切换到单主模式,查看节点情况:

#按照官方文档规则,单主模式下主fail了,应该是1.12这个server充当着
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST  | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| group_replication_applier | 0bbd0bcc-7223-11e9-a4fc-000c296aa366 | 192.168.1.12 |        3308 | ONLINE       |
| group_replication_applier | 18f64c9b-7223-11e9-bba2-000c293610f1 | 192.168.1.13 |        3308 | ONLINE       |
| group_replication_applier | 241b7e73-74d4-11e9-aef0-000c293af32c | 192.168.1.14 |        3308 | ONLINE       |
| group_replication_applier | 463679cf-7222-11e9-9459-000c29a6154a | 192.168.1.11 |        3306 | ONLINE       |
+---------------------------+--------------------------------------+--------------+-------------+--------------+

mysql>  SHOW STATUS LIKE 'group_replication_primary_member';
+----------------------------------+--------------------------------------+
| Variable_name                    | Value                                |
+----------------------------------+--------------------------------------+
| group_replication_primary_member | 463679cf-7222-11e9-9459-000c29a6154a |
+----------------------------------+--------------------------------------+

#kill掉1.11这个主,看看哪个成为新的主
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST  | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| group_replication_applier | 0bbd0bcc-7223-11e9-a4fc-000c296aa366 | 192.168.1.12 |        3308 | ONLINE       |
| group_replication_applier | 18f64c9b-7223-11e9-bba2-000c293610f1 | 192.168.1.13 |        3308 | ONLINE       |
| group_replication_applier | 241b7e73-74d4-11e9-aef0-000c293af32c | 192.168.1.14 |        3308 | ONLINE       |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
#果然,1.12这台server成为了主
mysql> SHOW STATUS LIKE 'group_replication_primary_member';
+----------------------------------+--------------------------------------+
| Variable_name                    | Value                                |
+----------------------------------+--------------------------------------+
| group_replication_primary_member | 0bbd0bcc-7223-11e9-a4fc-000c296aa366 |
+----------------------------------+--------------------------------------+

#再要想加入1.11这台,按照之前加入节点的步骤就行了

参考:https://dev.mysql.com/doc/refman/5.7/en/group-replication.html

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
存储 缓存 负载均衡
需要搭建一个高性能的文件系统?我推荐你试试它.....(上)
需要搭建一个高性能的文件系统?我推荐你试试它.....(上)
需要搭建一个高性能的文件系统?我推荐你试试它.....(上)
Web server failed to start. Port XXX was already in use.【完美解决方案】
Web server failed to start. Port XXX was already in use.【完美解决方案】
Web server failed to start. Port XXX was already in use.【完美解决方案】
Threejs创建天空和太阳
这篇文章讲解了如何使用Three.js中的Sky组件来创建真实的天空与太阳效果,包括调整天空的颜色、太阳的位置以及实现大气散射等技巧。
483 3
|
安全 网络安全 算法框架/工具
SSH高版本连接问题排查
【6月更文挑战第21天】SSH高版本连接问题排查
1071 0
|
11月前
|
存储 机器学习/深度学习 人工智能
获评最高等级!阿里云首批通过信通院企业用云治理能力成熟度评测
获评最高等级!阿里云首批通过信通院企业用云治理能力成熟度评测
383 11
|
数据挖掘 数据处理 索引
Python数据分析面试:NumPy基础与应用
【4月更文挑战第16天】了解并熟练运用NumPy是衡量Python数据分析能力的关键。本文探讨了面试中常遇到的NumPy问题,包括数组创建、属性、索引切片、数组运算、统计函数以及重塑和拼接,并提供了相关代码示例。同时强调了易错点,如混淆Python列表与NumPy数组、误解广播规则等,提醒在数据处理中注意性能和内存效率。掌握这些知识点将有助于提升数据分析面试表现和技能。
285 5
WK
|
Python
Python变量命名
在Python编程中,变量命名对代码的可读性和维护性至关重要。遵循PEP 8风格指南,变量名应使用小写字母和下划线分隔单词,保持简洁明了、描述性强,避免使用单字母、Python关键字和内置函数名,采用有意义的缩写,使用英文命名,保持命名风格一致,避免魔法数字,考虑上下文。正确示例:`user_name`、`order_quantity`;不正确示例:`n`、`q`。
WK
254 0
EMQ
|
开发工具
MQTT 5.0 报文解析 04:PINGREQ 与 PINGRESP
除了用于连接、发布和订阅的控制报文,MQTT 还有一类报文用于在客户端和服务端之间模拟心跳,以达到保持连接的目的,它们分别是 PINGREQ 报文和 PINGRESP 报文,我们通常也会称它们为心跳报文。
EMQ
493 0
MQTT 5.0 报文解析 04:PINGREQ 与 PINGRESP
|
C#
WPF技术之Slider控件
Slider控件是WPF中常用的用于选择范围值的控件之一。它可以通过拖动滑块来选择一个在指定范围内的数值。
7940 0
WPF技术之Slider控件
|
机器学习/深度学习 安全 Cloud Native
历史首次!阿里云与浙大斩获数据库顶会SIGMOD最佳论文,成果已在PolarDB中落地
数据库漏洞检测提速100倍,阿里云与浙大成果斩获202 3SIGMOD最佳论文奖