细细探究MySQL Group Replicaiton — 配置维护故障处理全集

来源:互联网 发布:货币资金的数据来源于 编辑:程序博客网 时间:2024/05/16 06:16

http://www.cnblogs.com/xinysu/p/6674832.html

 
 
     本文主要描述 MySQL Group Replication的简易原理、搭建过程以及故障维护管理内容。由于是新技术,未在生产环境使用过,本文均是虚拟机测试,可能存在考虑不周跟思路有误情况,欢迎交流指正。
 
如果转载,请注明博文来源: www.cnblogs.com/xinysu/   ,版权归 博客园 苏家小萝卜 所有。望各位支持! 
回到顶部(go to top)

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个节点,一个节点故障,是采用多数投票机制还是全部一致投票机制?
 
回到顶部(go to top)

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的配置情况。

  • 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
回到顶部(go to top)

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.localdomain410 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain611 192.168.9.242 sutest24212 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=1200114 transaction_write_set_extraction = XXHASH6415 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 = OFF18 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 = OFF21 loose-group_replication_single_primary_mode = true22 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 启动MGR12 start group_replication;13  14 #5 查看Error log,截图如下15 #error log如果有问题,拉到本文末端,对应找错误,如果没有解决,请google或者留言16  17 #6 关闭 group_replication_bootstrap_group18 SET GLOBAL group_replication_bootstrap_group=OFF;
复制代码
  
进入到数据目录,发现新建了几个文件:
  
*_apaplier.*  系列文件 提供 SQL_Thread 使用,存储同个组内其他SERVER的binnary log,这个文件在第一个组成员加入组的时候,可以在Error Log看到其安装信息。
*_recovery.* 系列文件 是做什么使用的呢,在第一个成员启动MGR的时候,并没有看到其相关信息,稍后解疑!
先在实例A上开始造数据,建立数据库mgr,建立表格tb1,INSERT部分数据,操作如下:
复制代码
#实例Amysql> create database mgr;Query OK, 1 row affected (0.01 sec)mysql> use mgrDatabase changedmysql> 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: 0mysql> insert into tb1(name) select @@server_id;Query OK, 1 row affected (0.00 sec)Records: 1  Duplicates: 0  Warnings: 0mysql> insert into tb1(name) select @@server_id;Query OK, 1 row affected (0.01 sec)Records: 1  Duplicates: 0  Warnings: 0mysql> insert into tb1(name) select @@server_id;Query OK, 1 row affected (0.00 sec)Records: 1  Duplicates: 0  Warnings: 0mysql> 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: 010 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仅提供读服务。
    

    在搭建的过程中,也理清了两个重要通道的使用情况:

  • 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 #实例A2 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 #实例B2 stop group_replication;3  4 #检查实例B,C的error log,发现实例A主动退出,group成员删除实例A
 
    这个时候,A,B均可以读写,但是不在GROUP中,业务目前在A上运行,C也可以读写,目前是主库。
 
连接实例C:
#实例cstop group_replication;
   
    这个时候,整个GROUP内的所有成员都依次自动退出了GROUP。

3.2.3 关闭 group_replication_single_primary_mode参数

    需要修改2个地方,第一个是动态修改参数,第二个是到配置文件中修改参数(防止DB服务重启,参数失效)!
复制代码
#动态修改#实例Aset global group_replication_single_primary_mode =OFF #实例Bset global group_replication_single_primary_mode =OFF #实例Cset 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的所有数据
 
复制代码
#实例Amysql> 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) #实例Bmysql> 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) #实例Cmysql> 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: 这里需要注意冲突处理机制,可以查看第五部分的故障模拟。
 
回到顶部(go to top)

4 管理维护

这部分内容主要涉及到几个系统表格,有点类似于 SQL SERVER中的DMV视图,详见下表。
idtable_schematable_nametypedescription1performance_schemareplication_group_members重要,常用查看GROUP成员。2performance_schemareplication_group_member_stats重要,常用当前SERVER在GROUP中的同步情况,查看applier通道的同步情况。3performance_schemareplication_connection_stats重要,常用当前server中各个通道的使用情况,applier通道是一定有显示,recovery通道看是否使用过,如果有则显示,没有则不显示。4performance_schemareplication_applier_stats重要,常用当前server中各个通道是否启用。5performance_schemaglobal_status重要,常用单主模式下,可以查看当前主库是哪个。6performance_schemareplication_applier_configuration不常用,了解即可 7performance_schemareplication_applier_status_by_coordinator不常用,了解即可 8performance_schemareplication_applier_status_by_worker不常用,了解即可 9performance_schemareplication_connection_configuration不常用,了解即可 10mysqlslave_master_info重要,不常用设置了master_info_repository=TABLE,所以master的相关信息会存储在这个表格。
如果使用GROUP中的SERVER备份数据库,恢复到时候,注意要清理这个表格。11mysqlslave_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详细信息,因为报错描述最清楚都在这里了。
回到顶部(go to top)

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来分别描述。

    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/backup33202 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_info2 truncate table mysql.slave_relay_log_info3  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新增

简要步骤
  1. 备份后执行apply log
  2. 新建实例,添加plugins引擎
  3. 替换数据目录
  4. 启动数据库
  5. 清理relay-log文件,清理slave_master_info跟slave_relay_log_info信息
  6. 查看当前的GTID序号是否与 xtrabackup_binlog_info记录一致,如果不一致,执行 set gtid_purged
  7. 重启数据库服务
  8. 检查group replication配置是否有误
  9. change master
  10. 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新增

简要步骤
  1. 新建实例,添加plugins引擎
  2. source 备份文件
  3. 清理relay-log文件,清理slave_master_info跟slave_relay_log_info信息
  4. 查看当前的GTID序号是否与备份文件前面记录一致,如果不一致,执行 set gtid_purged
  5. 检查group replication配置是否有误
  6. change master
  7. start group_replication
回到顶部(go to top)

6 问题记录

1 ip间隔是 逗号

2 不要有分号,本人就这么笨的开始!

3 port是使用端口号 ,非实例端口号

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出错了,是否是重复执行冲突了,好好处理下

回到顶部(go to top)

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个节点,一个节点故障,是采用多数投票机制还是全部一致投票机制?
 
参考文档:
mysql官方在20161212正式发布了group replication版本,官网详细地址:https://dev.mysql.com/doc/refman/5.7/en/group-replication.html
感谢京东的中文翻译:http://acmug.net/?p=164 ,某些地方字面直译,有些不好理解,如果感觉理解有误,可对照看下英文文档。 翻译中文文档下载地址:http://storage.360buyimg.com/brickhaha/Mysql.pdf
0 0