本文主要描述 MySQL Group Replication的简易原理、搭建过程以及故障维护管理内容。因为是新技术,未在生产环境使用过,本文均是虚拟机测试,可能存在考虑不周跟思路有误状况,欢迎交流指正。
1 What's Group Replication
主从复制,一主多从,主库提供读写功能,从库提供写功能。当一个事务在master 提交成功时,会把binlog文件同步到从库服务器上落地为relay log给slave端执行,这个过程主库是不考虑从库是否有接收到binlog文件,有可能出现这种状况,当主库commit一个事务后,数据库发生宕机,恰好它的binlog还没来得及传送到slave端,这个时候选任何一个slave端都会丢失这个事务,形成数据不一致状况。原理图以下:
为了不出现主从数据不一致的状况,MySQL引入了半同步复制,添加多了一个从库反馈机制,这个有两种方式设置:
- 主库执行完事务后,同步binlog给从库,从库ack反馈接收到binlog,主库提交commit,反馈给客户端,释放会话;
- 主库执行完事务后,主库提交commit ,同步binlog给从库,从库ack反馈接收到binlog,反馈给客户端,释放会话;

可是,可是,可是,问题来了,虽然知足了一主多从,读写分析,数据一致,可是,依旧有两个弊端:
- 写操做集中在MASTER服务器上;
- MASTER宕机后,须要人为选择新主并从新给其余的slave端执行change master(可自行写第三方工具实现,可是mysql的复制就是没提供,因此也算是弊端)
因而乎,官方感应到民间怨气以及业界压力,于2016年12月12日正式发布了MySQL Group Replication,此处应有掌声
那么,MySQL Group Replication能够提供哪些功能呢?
- 多主,在同一个group里边的全部实例,每个实例能够执行写操做,也就是每一个实例都执行Read-Write
- 注意一点,多主状况下,当执行一个事务时,须要确保同个组内的每一个实例都承认这个事务无冲突异常,才能够commit,若是设置的是单主,其余实例ReadOnly,则不须要进行上面的判断
- 多主状况下,事务并发冲突问题就凸显出来了,如何避免呢?数据库内部有一个认证程序,当不一样实例并发对同一行发起修改,在同个组内广播承认时,会出现并发冲突,那么会按照先执行的提交,后执行的回滚
- 弹性,同个Group Replication中,节点的加入或者移除都是自动调整;若是新加入一个节点,该节点会自动从Group的其余节点同步数据,直到与其余节点一致;若是移除一个节点,那么剩下的实例会自动更新,再也不向这个节点广播事务操做,固然,这里要注意,假设一个Group的节点有n个(max(n)=9,同个Group最多节点数为9),移除或者宕机的节点数应该小于等于 floor((n-1)/2) ,注意是向下取整;若是是单主模式,宕机的是单主,则人为选择新主后,其余节点也会自动重新主同步数据。
- 更高性能的同步机制
涉及知识点
故障探测( Failure Detection):
Group Replication中有一个故障检测机制,会提供某些节点可能死掉的信息,而后广播给同一个Group的各个节点,若是肯定宕机,那么组内的节点就会与它隔离开来,该节点即没法同步其余节点的传送过来的binlog events,也没法执行任何本地事务。
这里有个问题,故障探测中,假设N个节点,一个节点故障,是采用多数投票机制仍是所有一致投票机制?
2 配置要求与限制
2.1 数据库要求
2.1.1 innodb引擎
为何须要使用innodb引擎呢?在MySQL Group Replication中,事务以乐观形式执行,可是在提交时检查冲突,若是存在冲突,则会在某些实例上回滚事务,保持各个实例的数据一致性,那么,这就须要使用到 事务存储引擎,同事Innodb提供一些额外的功能,能够更好的管理和处理冲突,因此建议 业务使用表格使用inndb存储引擎,相似于系统表格mysql.user使用MyISAM引擎的表格,由于极少修改及添加,极少出现冲突状况。
2.1.2 主键
每一个须要复制的表格都必须定义一个显式主键,注意跟隐式主键区分(使用Innodb引擎的表格,若是没有指定主键,默认选择第一个非空的惟一索引做为主键,若是没有,则自动建立一个6个字节的rowid隐式主键)。这个主键能在冲突发生时启动极其重要的做用,同时,可以有效提升relay log的执行效率。
2.1.3 隔离级别
官网建议使用READ COMMITTED级别,除非应用程序依赖于REPLEATABLE READ,RC模式下没有GAP LOCK,比较好支持Innodb自己的冲突检测机制何组复制的内部分布式检测机制一块儿协同工做。不支持SERIALIZABLE隔离级别。
2.1.4 外键
不建议使用级联外键,若是旧库自己有外键,业务上没法去除而且使用的是多主模式,那么,请配置 group_replication_enforce_update_everywhere_check ,强制检查每一个组成员的级联检查,避免多主模式下执行级联操做形成的检测不到的冲突。
2.1.5 IPv4网络,网络性能稳定延迟小带宽充足
2.1.6 自增跟步长
这里须要注意到,搭建group的时候,每一个实例中的auto_increment_increment跟auto_increment_offset的配置状况。
html
- auto_increment_increment,在GROUP中范围在1-9(由于一个GROUP最多只能有9个组成员),GROUP中安装的时候,默认为7;
- auto_increment_offset,增加步长,GROUP安装过程,是等于@@server_id的,可是注意有个规则是,当 auto_increment_offset > auto_increment_increment的时候,则是忽略 auto_increment_offset的设置,第一个insert的从1开始,组内其余成员的初始值按照插入顺序 1+n*组员个数,若GROUP有3个成员,A,B,C,serverid分别为2243310,2243320,3423340,A先insert,C再insert,B最后insert,则初始值 A是1,B是9,C是6 (测试结论,未找到实际说明文档)
1 mysql> show global variables like 'auto_inc%';
2 +--------------------------+---------+
3 | Variable_name | Value |
4 +--------------------------+---------+
5 | auto_increment_increment | 7 |
6 | auto_increment_offset | 2143340 |
7 +--------------------------+---------+
8 2 rows in set (0.00 sec)
2.2 安装mysql_replication引擎前提
- master info and relay log info repositories
- master_info_repository
- set global master_info_repository ='table';
- relay_log_info_repository
- set global relay_log_info_repository=‘table';
- 若是不设置会报错,报错信息以下
- [ERROR] For the creation of replication channels the master info and relay log info repositories must be set to TABLE
- binlog_checksum
- binlog的校验方式应该设置为none
- 若是不设置,报错性能以下
- [ERROR] Plugin group_replication reported: 'binlog_checksum should be NONE for Group Replication'
2.3 其余参数要求
- binary log设置
- 须要启动记录binary log,任何复制都须要使用到二进制内容
- 在配置文件中添加 log-bin = [binlog存储路径及命名方式]
- 例子: log-bin = /data/mysql/mysql3310/logs/bin_log
- log-slave-updates设置
- 默认状况下,主库同步到从库执行的内容,是不产生binlog日志的,通常开启该参数是为了知足 多级复制,好比 A->B->C(A是B的主库,B是C的主库),那么这个时候B就须要开启这个参数记录从A同步到B上面的全部操做到binary log中,这样才能完整的同步到C上。
- 而在MGR中,组中的server须要记录从组接收和应用的全部事务,由于恢复的时候,是依赖域各个组的二进制日志内容的。
- 那么这个时候,可能就有个疑问,在多主模式下,假设实例A ,B , C三台中,每一个实例修改的内容都记录到binary log中,再同步给其余组成员,那在B上执行事务 tranb : update了一行数据,tranb提交后同步到 A跟C,各自执行后,因为启动了log-slave-updates设置,A跟C也生成了binary log,那么这些日志若是再同步回B,再执行一遍,不就可能出现问题了吗?实际上这个担心是多余的,在MGR中,启动了GTID模式,会检查GTID EXCUTED集合,若是是已经执行的,则不会再次执行。
- binary log格式
- MGR依赖以及与行复制格式
- binlog_format=row
- GTID模式启动
- 组复制使用全局事务标识符来记录哪些事务已在全部server实例上提交,从而判断哪些是已提交事务哪些是冲突事务,避免重复执行及数据不一致
- gtid_mode=ON
- transaction_write_set_extraction
- 这个神奇的参数5.7.6版本引入,用于定义一个记录事务的算法,这个算法使用hash标识来记录事务。若是使用MGR,那么这个hash值须要用于分布式冲突检测何处理,在64位的系统,官网建议设置该参数使用 XXHASH64 算法。
- transaction_write_set_extraction ='XXHASH64'
- 官网解释:Defines the algorithm used to generate a hash identifying the writes associated with a transaction. If you are using Group Replication, the hash value is used for distributed conflict detection and handling. On 64-bit systems running Group Replication, we recommend setting this to XXHASH64 in order to avoid unnecessary hash collisions which result in certification failures and the roll back of user transactions
3 搭建Mysql Group Replication
本次搭建采用3个实例,两个服务器,同一个网段,MGR的参数配置在配置文件中添加。
- 注意通信端口号的配置,它用于组成员之间的通信使用
- 请肯定当前MySQL版本为5.7.17或者以后版本
- 每一个实例的serverid必须是惟一标识,建议使用ip末端+端口描述
基础信息以下:
实例名
|
A
|
B
|
C |
IP
|
192.168.9.242
|
192.168.9.242
|
192.168.9.244
|
实例端口号
|
3310
|
3320
|
3340
|
Server-ID |
2423310
|
2423320
|
2443340
|
通信端口号
|
24201
|
24202
|
24404
|
MySQL Versoin
|
5.7.17
|
5.7.17
|
5.7.17
|
MGR参数配置方式
|
修改配置文件
|
修改配置文件
|
修改配置文件
|
3.1 单主模式(group_replication_single_primary_mode =ON)
3.1.1 主机名修改
为了方便后续管理维护以及一些没必要要的错误,强烈建议修改主机名,尤为是当同个GROUP里边的SERVER主机名都是同样的状况下,因为本人在虚拟机中测试,虚拟机的主机名都是同样的,致使后续出现了部分问题,建议修改。
注意在两台SERVER上都修改哈!
1 #查看当前主机名
2 hostname
3
4 #修改主机名
5 hostname sutest242
6
7 #进入vim /etc/hosts
8 #添加记录,不要修改默认的 127.0.0.1跟::1的记录,其余的系统服务会使用到的
9 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
10 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
11 192.168.9.242 sutest242
12 192.168.9.244 sutest244
配置后检查以下:
3.1.2 设置环境变量
关于GTID及日志信息记录相关参数(这部分的参数设置含义能够查看 第二部分:配置要求与限制
)
gtid_mode=on
enforce-gtid-consistency=on
binlog_gtid_simple_recovery=1
log-slave-updates=1
binlog_checksum=NONE
master_info_repository=TABLE
relay_log_info_repository=TABLE
关于MGR相关参数说明
transaction_write_set_extraction #记录事务的算法
group_replication_start_on_boot #是否随服务器启动而自动启动组复制
group_replication_bootstrap_group #引导组成员的组,这个用于第一次搭建MGR跟从新搭建MGR的时候使用
group_replication_group_name #此GROUP的名字,必须是一个有效的UUID,以此来区分整个内网里边的各个不的GROUP
group_replication_local_address #本地的IP地址字符串,host:port
group_replication_group_seeds #须要接受本实例的信息服务器IP地址字符串
group_replication_single_primary_mode #是否启动单主模式,若是启动,则本实例是主库,提供读写,其余实例仅提供读
group_replication_enforce_update_everywhere_checks #多主模式下,强制检查每个实例是否容许该操做
关于MGR相关参数配置
1 #动态配置:
2 set global transaction_write_set_extraction='XXHASH64';
3 set global group_replication_start_on_boot=OFF;
4 set global group_replication_bootstrap_group = OFF ;
5 set global group_replication_group_name= '9ac06b4e-13aa-11e7-a62e-5254004347f9'; #某个UUID
6 set global group_replication_local_address='192.168.9.242:24201';
7 set global group_replication_group_seeds ='192.168.9.242:24201,192.168.9.242:24202,192.168.9.242:24401';
8 set global group_replication_ip_whitelist = '127.0.0.1/8,192.168.9.0/24';
9 set global group_replication_single_primary_mode=True;
10 set global group_replication_enforce_update_everywhere_checks=False;
11
12 #cnf文件配置:
13 server-id=12001
14 transaction_write_set_extraction = XXHASH64
15 loose-group_replication_group_name = '9ac06b4e-13aa-11e7-a62e-5254004347f9'
16 loose-group_replication_ip_whitelist = '127.0.0.1/8,192.168.9.0/24'
17 loose-group_replication_start_on_boot = OFF
18 loose-group_replication_local_address = '192.168.9.242:24201'
19 loose-group_replication_group_seeds = '192.168.9.242:24201,192.168.9.242:24202,192.168.9.242:24401'
20 loose-group_replication_bootstrap_group = OFF
21 loose-group_replication_single_primary_mode = true
22 loose-group_replication_enforce_update_everywhere_checks = false
这一步这里采用配置文件添加的方式,
添加成功后重启数据库服务。
3.1.3 创建复制帐号
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.%' IDENTIFIED BY 'replforslave';
3.1.4 安装引擎
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
若是出现1123错误,请查看当前的数据库版本是不是5.7.17及以后的版本,只有这些版本才有grou_replication插件
ERROR 1123 (HY000): Can't initialize function 'group_replication'; Plugin initialization function failed.
安装后,引擎默认会建立一个用户 _gr_user,提供group_replication引擎内部使用,其权限以下:
检查是否安装成功,show plugins;
来到了这一步,离成功已经很近了,注意检查 步骤1-4,必须在每一个实例或者server上都配置一遍。
3.1.5 配置Group
按照先把实例A加入Group中,因为是第一个加入Group中,须要启动group_replication_bootstrap_group,引导组,实例A加入成功后,陆续加入实例B及实例C。
首先,对实例A进行操做:
1 #实例A
2 #1 查看当前的group replication相关参数是否配置有误
3 show global variables like 'group%';
4
5 #2 启动 group_replication_bootstrap_group
6 SET GLOBAL group_replication_bootstrap_group=ON;
7
8 #3 配置MGR
9 CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
10
11 #4 启动MGR
12 start group_replication;
13
14 #5 查看Error log,截图以下
15 #error log若是有问题,拉到本文末端,对应找错误,若是没有解决,请google或者留言
16
17 #6 关闭 group_replication_bootstrap_group
18 SET GLOBAL group_replication_bootstrap_group=OFF;
进入到数据目录,发现新建了几个文件:
*_apaplier.* 系列文件 提供 SQL_Thread 使用,存储同个组内其余SERVER的binnary log,这个文件在第一个组成员加入组的时候,能够在Error Log看到其安装信息。
*_recovery.* 系列文件 是作什么使用的呢,在第一个成员启动MGR的时候,并无看到其相关信息,稍后解疑!
先在实例A上开始造数据,创建数据库mgr,创建表格tb1,INSERT部分数据,操做以下:
#实例A
mysql> create database mgr;
Query OK, 1 row affected (0.01 sec)
mysql> use mgr
Database changed
mysql> create table tb1(id int primary key auto_increment not null,name varchar(100));
Query OK, 0 rows affected (0.10 sec)
mysql> insert into tb1(name) select @@server_id;
Query OK, 1 row affected (0.09 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into tb1(name) select @@server_id;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into tb1(name) select @@server_id;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into tb1(name) select @@server_id;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from tb1;
+----+---------+
| id | name |
+----+---------+
| 6 | 2423310 |
| 13 | 2423310 |
| 20 | 2423310 |
| 27 | 2423310 |
+----+---------+
4 rows in set (0.00 sec)
mysql> show master status;
+----------------+----------+--------------+------------------+------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+----------------+----------+--------------+------------------+------------------------------------------+
| bin_log.000002 | 1795 | | | 9ac06b4e-13aa-11e7-a62e-5254004347f9:1-7 |
+----------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.00 sec)
模拟数据操做
接着,对实例B 进行操做:
1 #实例B
2 #1 查看当前的group replication相关参数是否配置有误
3 show global variables like 'group%';
4
5 #2 配置MGR
6 CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
7
8 #3 启动MGR
9 start group_replication;
10
11 #4 查看Error log,截图以下
12 #error log若是有问题,拉到本文末端,对应找错误,若是没有解决,请google或者留言

经过errrlog,能够详细看到启动过程的全部步骤信息,因为新增数据,致使实例B须要使用到 group_replication_recovery 通道来恢复数据。可是是怎么一个恢复过程呢?查看 *_recovery.* 系列文件 都是只有文件头没有binlog内容的文件。
在加入实例C以前,再次在实例A上造数据,此次造多多数据。新建表格tb2,设置2个大字段,而后insert 2w+的数据量。
1 #实例A
2 mysql> use mgr
3 Database changed
4 mysql> create table tb2(id int auto_increment primary key not null,namea varchar(8000),nameb varchar(8000));
5 Query OK, 0 rows affected (0.03 sec)
6
7 mysql> insert into tb2(namea,nameb) select repeat('a',8000),repeat('b',8000);
8 Query OK, 1 row affected (0.02 sec)
9 Records: 1 Duplicates: 0 Warnings: 0
10
11 #insert 自行操做,看试验须要,本次须要大量数据来recovery,因此后面采用 insert into tb2 .. select .. from tb2 方式造数据 2w+行
最后,对实例C 进行操做:
1 #实例C
2 #1 查看当前的group replication相关参数是否配置有误
3 show global variables like 'group%';
4
5 #2 配置MGR
6 CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
7
8 #3 启动MGR
9 start group_replication;
10
11 #4 查看Error log,截图以下
12 #error log若是有问题,拉到本文末端,对应找错误,若是没有解决,请google或者留言
经过errrlog,能够详细看到启动过程的全部步骤信息,因为新增数据,致使实例C须要使用到 group_replication_recovery 通道来恢复数据,这跟实例B是如出一辙的过程,可是,因为前期实例A造了大量的数据,因此在整个recovery的过程当中,能够查看到 *_recovery.* 系列文件 的变化状况。
经过error log大小的变化,是经过group_replication_recovery 通道来恢复数据,须要恢复的binary log是存放在
*_recovery.* 系列文件 ,经过本次recovery 文件查看,发现,在recovery过程当中,通道内的IO_THREAD拉去日志存储在 *_recovery.* 系列文件 中,当通道内的 SQL_Thread 完成日志应用后,则会删除掉 *_recovery.* 系列文件 文件,新建空文件,表明已经没有数据须要恢复。
至此,单主模式已搭建结束,实例A可提供读写,可是实例B跟实例C仅提供读服务。
在搭建的过程当中,也理清了两个重要通道的使用状况:mysql
- group_replication_applier 通道 提供组内成员向 MASTER 实时同步binlog日志使用,这个通道内IO_thread拉取到的日志存放在 *_apaplier.* 系列文件中,再经过SQL_Thread应用到组内的各个SERVER上。
- group_replication_recovery 通道 提供 首次加入GROUP或者从新加入GROUP时恢复数据使用,这个通道内 IO_thread拉取到的日志存放在 *_recovery.* 系列文件中,再经过SQL_Thread应用到组内的各个SERVER上,应用结束后,删除全部 *_recovery.* 系列文件 ,从新创建新的 *_recovery.* 系列文件。
能够经过P_S库中的表格查询使用状况:SELECT * FROM mysql.slave_relay_log_info
3.2 多主模式(group_replication_single_primary_mode =OFF)
多主模式如何配置呢,其实跟 单主模式的流程如出一辙,只须要修改 3.1 单主模式 中第二部 配置环境变量中,把 group_replication_single_primary_mode 参数设置成关闭状态便可,而后按照 单足模式的一直执行就能够了。
# 动态修复方式
set global group_replication_single_primary_mode=OFF;
# 配置文件修改方式
loose-group_replication_single_primary_mode = OFF
可是,既然说到配置多主模式,除了从头就直接配置多主外,还有一种状况是,原本是单主模式,如今修改成多主模式,这个转换过程,则是这部分要来描述的。
首先,考虑到的是,可否直接在多主模式运行的状况下,就直接动态修改这个参数呢?由于这个参数是能够动态调整,BUT,在 GROUP_REPLICATION 运行的过程当中,是不能修改这个参数的,会友好的提示您:
因此,须要新停掉GROUP_REPLICATION。
操做流程:业务端链接IP处理 -> GROUP内成员逐个依次主动退出GROUP -> 关闭 group_replication_single_primary_mode参数-> 逐个启动GROUP内的SERVER
3.2.1 业务端链接IP处理
对程序端端影响:若是是程序直连主库,则不须要操心这个过程,可是若是是经过第三方工具检查GROUP中的主库是哪一个的话,须要先修改第三方工具直连原主库,由于全部Group内的成员都要中止服务,若是都是自动判断的话,最后会找不到GROUP中的成员的,因此,在开始切换的时候,就须要业务方固定读写在实例A上。
3.2.2 GROUP内成员逐个依次主动退出GROUP
链接实例A:
1 #实例A
2 stop group_replication;
3
4 #检查实例B,C的error log,发现实例A主动退出,group成员删除实例A
Error Log内容以下:
这个时候,A可读写,可是不在group中,其binlog内容不会在组内同步;C升级自动升级为主库,可读写,binlog会同步到B上。
这里的主库升级,是看MEMBER_ID的升序排序状况,最小的升级为主库。
在B上经过表格 replication_group_members跟global_status,能够查看如今的组成员以及主库是哪一个。查看截图以下:
链接实例B:
1 #实例B 2 stop group_replication; 3 4 #检查实例B,C的error log,发现实例A主动退出,group成员删除实例A
这个时候,A,B都可以读写,可是不在GROUP中,业务目前在A上运行,C也能够读写,目前是主库。
链接实例C:
#实例c
stop group_replication;
这个时候,整个GROUP内的全部成员都依次自动退出了GROUP。
3.2.3 关闭 group_replication_single_primary_mode参数
须要修改2个地方,第一个是动态修改参数,第二个是到配置文件中修改参数(防止DB服务重启,参数失效)!
#动态修改
#实例A
set global group_replication_single_primary_mode =OFF
#实例B
set global group_replication_single_primary_mode =OFF
#实例C
set global group_replication_single_primary_mode =OFF
#配置文件添加
#实例A的cnf文件中修改
loose-group_replication_single_primary_mode = OFF
#实例B的cnf文件中修改
loose-group_replication_single_primary_mode = OFF
#实例C的cnf文件中修改
loose-group_replication_single_primary_mode = OFF
为了模拟有业务在实例A上操做,在实例A上建立表格 tb4,并导入tb2的全部数据
#实例A
mysql> create table tb4 like tb2;
Query OK, 0 rows affected (0.18 sec)
mysql> insert into tb4 select * from tb2;
Query OK, 20480 rows affected (33.13 sec)
Records: 20480 Duplicates: 0 Warnings: 0
3.2.4 逐个启动GROUP内的SERVER
首先针对实例A启动,而后启动实例B,紧接着启动实例C。这个过程当中,每加入一个组成员,记得去看error log是否有报错。
当A启动的时候,能够看到成了一个新的GROUP,B加入到时候,须要经过 group_replication_recovery 通道恢复数据,C加入到时候,也须要经过 group_replication_recovery 通道恢复数据,这部分的内容跟 3.1. 5 配置Group 中的errorlog内容差很少,这里就不作截图分析。
#实例A
#须要启动 group_replication_bootstrap_group 引导组,启动后须要关闭,防止脑裂
mysql> set global group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)
mysql> CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.02 sec)
mysql> START GROUP_REPLICATION;
Query OK, 0 rows affected (1.16 sec)
mysql> set global group_replication_bootstrap_group=Off;
Query OK, 0 rows affected (0.00 sec)
#实例B
mysql> CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.04 sec)
mysql> start group_replication;
Query OK, 0 rows affected (4.31 sec)
#实例C
mysql> CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.07 sec)
mysql> start group_replication;
Query OK, 0 rows affected (3.83 sec)
3.2.5 检查如今GROUP状况
目前GROUP中的各个成员都关闭了super_read_only选项,提供了读写服务,因为三个都为主库,属于多主状况,因此 global_status中没法查看到主库是哪一个,由于这个GROUP中,每一个SERVER都是MASTER。
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 2ec0fecd-16a2-11e7-97e1-52540005b8e1 | sutest244 | 3340 | ONLINE |
| group_replication_applier | 94e39808-15ed-11e7-a7cf-52540005b8e2 | sutest242 | 3310 | ONLINE |
| group_replication_applier | 9b78d231-15ed-11e7-a82a-52540005b8e2 | sutest242 | 3320 | ONLINE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.21 sec)
mysql> select * from performance_schema.global_status where variable_name like '%group%';
+----------------------------------+----------------+
| VARIABLE_NAME | VARIABLE_VALUE |
+----------------------------------+----------------+
| group_replication_primary_member | |
+----------------------------------+----------------+
1 row in set (0.35 sec)
mysql> show global variables like 'group_replication_single_primary_mode';
+---------------------------------------+-------+
| Variable_name | Value |
+---------------------------------------+-------+
| group_replication_single_primary_mode | OFF |
+---------------------------------------+-------+
1 row in set (0.33 sec)
mysql> show global variables like 'super%';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| super_read_only | OFF |
+-----------------+-------+
1 row in set (1.20 sec)
至此,多主模式已搭建结束,实例A、B、C都可提供读写。PS: 这里须要注意冲突处理机制,能够查看第五部分的故障模拟。
4 管理维护
这部份内容主要涉及到几个系统表格,有点相似于 SQL SERVER中的DMV视图,详见下表。
id |
table_schema |
table_name |
type |
description |
1 |
performance_schema |
replication_group_members |
重要,经常使用 |
查看GROUP成员。 |
2 |
performance_schema |
replication_group_member_stats |
重要,经常使用 |
当前SERVER在GROUP中的同步状况,查看applier通道的同步状况。 |
3 |
performance_schema |
replication_connection_stats |
重要,经常使用 |
当前server中各个通道的使用状况,applier通道是必定有显示,recovery通道看是否使用过,若是有则显示,没有则不显示。 |
4 |
performance_schema |
replication_applier_stats |
重要,经常使用 |
当前server中各个通道是否启用。 |
5 |
performance_schema |
global_status |
重要,经常使用 |
单主模式下,能够查看当前主库是哪一个。 |
6 |
performance_schema |
replication_applier_configuration |
不经常使用,了解便可 |
|
7 |
performance_schema |
replication_applier_status_by_coordinator |
不经常使用,了解便可 |
|
8 |
performance_schema |
replication_applier_status_by_worker |
不经常使用,了解便可 |
|
9 |
performance_schema |
replication_connection_configuration |
不经常使用,了解便可 |
|
10 |
mysql |
slave_master_info |
重要,不经常使用 |
设置了master_info_repository=TABLE,因此master的相关信息会存储在这个表格。 若是使用GROUP中的SERVER备份数据库,恢复到时候,注意要清理这个表格。 |
11 |
mysql |
slave_relay_log_info |
重要,不经常使用 |
设置了relay_log_info_repository=TABLE,因此master的相关信息会存储在这个表格。 若是使用GROUP中的SERVER备份数据库,恢复到时候,注意要清理这个表格。 |
4.1 查看GROUP中的成员有哪些
SELECT * FROM performance_schema.replication_group_members
4.2 单主模式下主库是哪一个
SELECT * FROM performance_schema.replication_group_members;
SELECT * FROM performance_schema. global_status;
两个查询出来的UUID一致的为 主库。
4.3 检查数据库是否正常提供读写服务
show global variables like 'super%';
SELECT * FROM performance_schema.replication_group_members;
若是super_read_only是启动的,那么该成员仅提供读服务;
若是super_read_only是关闭的,而且 replication_group_members 中正常的成员n 知足 2n+1 > 整个GROUP成员个数,而且该成员的 member state是online,则该成员可提供读写服务。
4.4 检查数据库是否复制出现问题
能够经过表格replication_group_members ,replication_group_member_stats ,replication_connection_stats ,replication_applier_stats 查看
重点注意各个 组成员的 ERROR LOG详细信息,由于报错描述最清楚都在这里了。
5 故障模拟及处理
节选测试过程的图,跟以前配置的GROUP有些不一致,理解注重思路便可,部分测试细节没有再次描述。算法
5.1 单主模式
5.1.1 主库宕机,如何自动选择新主库?各个实例之间的super_read_only模式如何切换?
select * from performance_schema.replication_group_members;
select * from performance_schema.global_status where VARIABLE_NAME='group_replication_primary_member';
show global variables like 'server_uuid';
show global variables like 'super%';
select * from performance_schema.replication_connection_status;
select * from performance_schema.replication_applier_status;





模拟group中,有三个实例,端口分别为 3320,3330,3340,用简称来 m3320、m3330、m3340来分别描述。sql
m3330在属于主库,模拟其主库宕机,使用 kill 进程方式,当m3330宕机后,m3320及m3340检查到 timeout reading,则会从group_member中剔除该实例,同时检测宕机实例是否小于 floor((n-1)/2) (n为group中全部实例个数),若是知足,则启动新的GROUP,按照GROUP中各个实例的UUID进行 升序排序,选择第一个做为新的主库,因为新主库以前是super_read_only状态,仅支持只读,升级为新主库后,会执行 ,不设置 super_read_only,关闭此参数,那么新主库则是可提供读写服务,原先的从库如今依旧为从库,super_read_only依旧为启动状态,仅提供读服务。
5.1.2 主库宕机后,恢复,从新加入group
旧主库恢复后,检查GROUP_REPLICATION相关参数,是否设置有误,它须要以一个从库的方式加入,详见 GROUP配置的参数说明。
若是参数无误,执行change master,而后start 便可。
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
START GROUP_REPLICATION;
其余两个节点检查链接状况,链接无误后,加入group中,更新 GROUP Member,同时开始同步差别binlog日志内容。
5.1.3 从库宕机1台,影响状况
kill 3330进程,模拟从库宕机,发现剩下实例检测到 m3330异常,从 group中删除,主库m3320照常提供读写服务,从库m3340照常提供读服务。
5.1.4 从库宕机2台,影响状况
基于3的基础上,再次kill 3340进程,模拟从库宕机,主库3320检查到 m3340异常,可是没有删除该 成员,而是即是为 unreachable,代表该成员可能因为崩溃或者意外被断开而致使的不可访问。
或者(两个从库宕机的时刻很是接近,则来不及判断剔除出group)
对仅存活动 m3320 执行查询操做,是正常状况。可是DDL及DML 操做,均处于等待状态,而且,error log也无报错状况。
这个时候,若是想要恢复主库读写服务,需中止group(这里有个疑问,查看replication_applier_status,主库状态正常;可是不提供读写应该从哪一个地方判断呢,难道是group_member的正常个数不知足group的正常个数要求,则不提供服务?除了stop group_relication和新加入节点外,还有其余方式处理吗?
)
5.1.5 新增从库:innobackupex新增(这个须要留意)
选择在 m3320备份实例,备份结束后apply log。
1 innobackupex --datadir=/data/mysql/mysql3320/data/ --user=root --password=ycf.com --no-timestamp --socket=/tmp/mysql3320.sock /data/backup3320
2 innobackupex --apply-log /data/backup3320
第一次启动数据库时,报错,找不到relay log文件,由于拷贝过来的时候 ,备份库指定参数以下,mysql库中的master_relay_log_info指定了relay log的相关信息,可是如今没有找到文件,数据库会自动建立 applier跟recovery系列文件。
master_info_repository=TABLE
relay_log_info_repository=TABLE
因此须要进入数据库中,
truncate 两个表格:mysql.slave_master_info, mysql.slave_relay_log_info ,而后删除 applier跟recovery系列文件 。
1 truncate table mysql.slave_master_info
2 truncate table mysql.slave_relay_log_info
3
4 rm -rf applier系列文件
5 rm -rf recovery系列文件
查看下备份的GTID集合,以下
重启数据库服务,进入数据库,从新配置GTID集合与备份中的一致,启动GROUP_REPLICATION。
RESET MASTER;
SET @@GLOBAL.GTID_PURGED='9ac06b4e-13aa-11e7-a62e-5254004347f9:1-10';
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
START GROUP_REPLICATION;
5.1.6 新增从库:mysqldump新增(这个须要留意)
备份数据库实例:
/usr/local/mysql5717/bin/mysqldump --socket=/tmp/mysql3320.sock -uroot -p --all-databases > ~/mysql3320.sql
这里有个小TIPS,我的建议,创建一个新的实例后,在新实例中安装 好 group_replication 引擎,不要等到source后再安装,这样的好处是:避免直接在恢复的数据库实例上安装引擎,会出现各类错误。
在服务器上先安装 group_replication引擎,而后再source数据,避免source数据后因为环境问题致使group_replication引擎安装有问题
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
成功后source /data/mysql3320.sql
检查当前的binlog跟gtid使用状况,show master status;
因为目前的使用状况跟mysqldump中的 gtid_purge不一致,从新拷贝下mysql3320.sql中的 gtid_purged语句,注意,若是当前的gtid_excuted不为空,则须要重置下master相关信息,reset master后执行gtid_purge语句。
SET @@GLOBAL.GTID_PURGED='9ac06b4e-13aa-11e7-a62e-5254004347f9:1-18'; #看GTID集合是否一致
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
START GROUP_REPLICATION;
5.2 多主模式
5.2.1 单主模式切换多主模式
这部分参考第三部分的第二节,多主模式。
简要步骤:
1 先由 从主库开始,逐一逐一中止group replication
2 设置group_replication_single_primary_mode 关闭
3 依次启动GROUP replication
测试内容:
1 整个GROUP中每一个SERVER同时执行一个DML语句
2 整个GROUP中每一个SERVER同时执行一个DDL语句
测试结论:
严重注意,若是在同时提交DDL语句,则在每一个实例都是能够提交成功,可是同步到各个实例的时候会发生报错,group_replication出现 error错误,全部实例启动super_read_only只读状况,整个group不提供 写操做,须要人为接入修复。因此DDL语句,建议在设计的时候,就专门只有一个实例能够执行DDL语句,人为默认在某一台上执行DDL语句,而不是每台都执行,避免没必要要的冲突。
5.2.2 宕机一台总体影响
kill 进程,其余实例检车连接有问题后,剔除该节点,正常操做。
5.2.3 宕机后从新加入
启动数据库实例后,记得检查 group_replication_single_primary_mode是不是关闭状态,若是不是,注意启动,要否则会因为模式不一致报错,
set global group_replication_single_primary_mode=OFF;
正常执行
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
START GROUP_REPLICATION;
5.2.4 宕机超过合理个数,总体影响(非一个个慢慢宕机,而是一口气宕机超过合理个数)
5台server端,一口气停机了3台,则3台的status修改成UNREACHABLE,剩下的2台为ONLINE,虽然super_read_only是关闭的状态,可是这两台server不提供写功能,仅提供读功能。
这里注意下,若是这个时候,发生DML操做,则会挂起该操做,一直处于等待状态,其余连接能够正常链接数据库进行操做;可是若是发生DDL操做,这个时候,不只该会话处于等待状态,并且其余新的链接将没法执行user dbname(涉及操做的DBname)进入到该数据库中进行 任何查询操做,可是能够在其余数据库上 使用 dbname.tbname 方式查询,好比select * from dbgroup.alld!
仅剩下的一台主库竟然不提供读写,除非关闭stop group_replication!
关闭后,error log中会提示事务回滚信息。
5.2.5 新增DB:innobackupex新增
简要步骤
- 备份后执行apply log
- 新建实例,添加plugins引擎
- 替换数据目录
- 启动数据库
- 清理relay-log文件,清理slave_master_info跟slave_relay_log_info信息
- 查看当前的GTID序号是否与 xtrabackup_binlog_info记录一致,若是不一致,执行 set gtid_purged
- 重启数据库服务
- 检查group replication配置是否有误
- change master
- start group_replication
#部分参考SQL
SET @@GLOBAL.GTID_PURGED='9ac06b4e-13aa-11e7-a62e-5254004347f9:1-26:1000004';
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery';
START GROUP_REPLICATION;
5.2.6 新增DB:mysqldump新增
简要步骤
- 新建实例,添加plugins引擎
- source 备份文件
- 清理relay-log文件,清理slave_master_info跟slave_relay_log_info信息
- 查看当前的GTID序号是否与备份文件前面记录一致,若是不一致,执行 set gtid_purged
- 检查group replication配置是否有误
- change master
- start group_replication
6 问题记录
1 ip间隔是 逗号数据库
2 不要有分号,本人就这么笨的开始!bootstrap
3 port是使用端口号 ,非实例端口号vim
4 [ERROR] Plugin group_replication reported: 'This member has more executed transactions than those present in the group. Local transactions: 32538cbf-12fc-11e7-af43-5254004347f9:1-5 > Group transactions: 2236bd6b-12fc-11e7-a706-5254004347f9:1-16服务器

[ERROR] Plugin group_replication reported: 'This member has more executed transactions than those present in the group. Local transactions: 32538cbf-12fc-11e7-af43-5254004347f9:1-5 > Group transactions: 2236bd6b-12fc-11e7-a706-5254004347f9:1-16,9ac06b4e-13aa-11e7-a62e-5254004347f9:1'
[ERROR] Plugin group_replication reported: 'The member contains transactions not present in the group. The member will now exit the group.'网络
[Note] Plugin group_replication reported: 'To force this member into the group you can use the group_replication_allow_local_disjoint_gtids_join option'并发
- 解决
- set global group_replication_allow_local_disjoint_gtids_join=ON;(可是实际上这种方法治标不治本)
- 建议仍是在搭建group_replication的时候,在start group_replication以前,reset master,重置全部binary log,这样就不会出现各个实例之间的日志超前影响;可是这里要考虑是否影响到旧主从。
5 [ERROR] Plugin group_replication reported: 'Table te does not have any PRIMARY KEY. This is not compatible with Group Replication'
表格须要添加主键
6 mysql> insert into ct(id,name) select 2,'b'; ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
只读模式下,不提供写服务。
7 [ERROR] Plugin group_replication reported: 'Transaction cannot be executed while Group Replication is on ERROR state. Check for errors and restart the plugin' 2017-03-29T15:46:13.619141Z 31 [ERROR] Run function 'before_commit' in plugin 'group_replication' failed
GROUP出错了,是不是重复执行冲突了,好好处理下
7 未解决问题
1 能够经过 show slaves status for channel 'group_replication_recovery' 查看recovery通道执行状况,可是怎么看 applier呢?(show slaves status for channel 'group_replication_applier'报错 )
2 当宕机超过有效个数时,查看replication_applier_status,状态正常,可是ONLINE的server实际上不提供写服务,仅提供读服务,能够经过什么方式快速判断呢?我的认为是如下判断,是否有更好的方式?
show global variables like 'super%';
SELECT * FROM performance_schema.replication_group_members;
若是super_read_only是启动的,那么该成员仅提供读服务;
若是super_read_only是关闭的,而且 replication_group_members 中正常的成员n 知足 2n+1 > 整个GROUP成员个数,而且该成员的 member state是online,则该成员可提供读写服务。
3 当宕机超过有效个数时,ONLINE的server仅提供读服务,若是须要启动写服务,目前我的测试结果是只有两种方案恢复写服务:当前SERVER,执行stop group_replication;恢复另外的异常SERVER变正常。是否还有其余方式?
4 GROUP中剔除一个成员,假设N个节点,一个节点故障,是采用多数投票机制仍是所有一致投票机制?
参考文档: