Mysql(四)全同步复制(组复制)

关于组复制:详细解读组复制参考

MySQL Group Replication(简称MGR)是MySQL官方于2016年12月推出的一个全新的高可用与高扩展的解决方案。组复制是MySQL5.7版本出现的新特性, 它提供了高可用、高扩展、高可靠的MySQL集群服务。MySQL组复制分单主模式和多主模式,mysql 的复制技术仅解决了数据同步的问题,如果 master 宕机,意味着数据库管理员需要介入,应用系统可能需要修改数据库连接地址或者重启才能实现。(这里也可以使用数据库中间件产品来避免应用系统数据库连接的 问题,例如 mycat 和 atlas 等产品)。组复制在数据库层面上做到了,只要集群中大多数主机可用,则服务可用,也就是说3台服务器的集群,允许其中1台宕机。

1、组复制的两种模式

-  在单主模式下, 组复制具有自动选主功能,每次只有一个 server成员接受更新;
-  在多主模式下, 所有的 server 成员都可以同时接受更新;

2、组复制原理

组复制是一种可用于实现容错系统的技术。 复制组是一个通过消息传递相互交互的server集群。通信层提供了原子消息(atomic message)和完全有序信息交互等保障机制,实现了基于复制协议的多主更新。复制组由多个 server成员构成,并且组中的每个server 成员可以独立地执行事务。但所有读写(RW)事务只有在冲突检测成功后才会提交。只读(RO)事务不需要在冲突检测,可以立即提交。句话说, 对于任何 RW 事务,提交操作并不是由始发 server 单向决定的,而是由组来决定是否提交。准确地说,在始发 server 上,当事务准备好提交时,该 server 会广播写入值(已改变的行)和对应的写入集(已更新的行的唯一标识符)。然后会为该事务建立一个全局的顺序。最终,这意味着所有 server 成员以相同的顺序接收同一组事务。因此, 所有 server 成员以相同的顺序应用相同的更改,以确保组内一致。

基于组的复制(Group-basedReplication)是一种被使用在容错系统中的技术。Replication-group(复制组)是 由能够相互通信的多个服务器(节点)组成的。在通信层,Groupreplication实现了一系列的机制:比如原子消息(atomicmessage delivery)和全序化消息(totalorderingof messages)。这些原子化,抽象化的机制,为实现更先进的数据库复制方案提供了强有力的支持。MySQL Group Replication正是基于这些技术和概念,实现了一种多主全更新的复制协议。

简而言之,一个Replication-group就是一组节点,每个节点都可以独立执行事务,而读写事务则会在于group内的其他节点进行协调 之后再commit。因此,当一个事务准备提交时,会自动在group内进行原子性的广播,告知其他节点变更了什么内容/执行了什么事务。
这种原 子广播的方式,使得这个事务在每一个节点上都保持着同样顺序。这意味着每一个节点都以同样的顺序,接收到了同样的事务日志,所以每一个节点以同样的顺序重 演了这些事务日志,最终整个group保持了完全一致的状态。然而,不同的节点上执行的事务之间有可能存在资源争用。这种现象容易出现在两个不同的并发事 务上。

假设在不同的节点上有两个并发事务,更新了同一行数据,那么就会发生资源争用。面对这种情况,GroupReplication判定先提交的事务为 有效事务,会在整个group里面重演,后提交的事务会直接中断,或者回滚,最后丢弃掉。因此,这也是一个无共享的复制方案,每一个节点都保存了完整的数 据副本。看下图描述了具体的工作流程,能够简洁的和其他方案进行对比。这个复制方案,在某种程度上,和数据库状态机(DBSM)的Replication 方法比较类似。

主从复制:

传统的MySQL复制提供了一种简单的主从复制方法。有一个主库,一个或多个从库。主库执行并提交事务,然后通过二进制日志将事务相关的事件异步发送到从库,以便重放。这是一个无共享系统,默认情况下所有服务器都拥有完整的数据副本。

 

  半同步复制为异步复制协议添加了一个同步步骤。这意味着主库在提交时等待至少一个从库确认它已收到该事务,才会继续提交操作。

 

以上两个图分别表示MySQL异步复制协议以及它的半同步变体。对角箭头表示服务器之间交换的消息或服务器与客户端应用程序之间交换的消息。

组复制

组由多个服务器构成,通过传递消息进行交互,通信层保证原子消息传递。MGR构建于此通信层抽象之上,并实现了多主更新复制协议。组中的每个服务器独立地执行事务,但是所有读写事务只有在得到组的批准后才会提交。只读事务在组内不需要协调,因此立即提交。对于任何读写事务,当事务准备好在始发服务器处提交时,服务器以原子方式广播写入值(更改的行)和对应的写入集(更新的行的唯一标识符),然后将该事务加入全局事务列表。最终所有服务器都以相同的顺序接收并应用相同的事务集,所以它们在组内保持一致。

        不同服务器上并发执行的事务之间可能存在冲突。MGR在certify过程中检查并发事务的写集来检测这种冲突。如果在不同服务器上执行的两个并发事务更新同一行,则存在冲突。解决方案是先到事务提交,后到事务回滚,即按顺序第一个事务在所有服务器提交,而第二个事务在在原始服务器上回滚并在组中的其它服务器中删除。这实际上体现的是多主分布式事务的首个提交获胜原则。

 

需要注意:MySQL组复制是一种 share-nothing 复制方案,其中每个 server 成员都有自己的完整数据副本

实验配置:

前提准备:

实验需要三台虚拟机server1 server2 server3
这三台虚拟机没有主从之分,只有一个主节点server1,三台虚拟机上面的配置都是一样的,展示组节点上虚拟机的配置。在组节点的虚拟机上,可以查看三台虚拟机是否配置成功!
在主从复制中,备服务器并没有上线,而在组复制中,之前的备服务器也上线,也就是说,三台虚拟机都是既可写也可读

组复制的应用场景:

  • 弹性复制:服务器的数量能够动态增加或减少,并且尽可能减小副作用,例如云数据库服务。
  • 高可用分片:分片是实现写扩展的流行方法。使用MGR实现高可用分片,其中每个分片映射到复制组。
  • 主从复制的替代方案:在某些情况下,使用单个主服务器会使其成为热点,写入整个组会更具可扩展性。

server1(master)节点:

1.关闭mysqld

systemctl stop mysqld

2.删除mysql数据  ##注意 :删除数据之前先复制uuid /var/lib/mysql/auto.cnf

rm -fr /var/lib/mysql/*

3.修改配置文件  官方文档有详细配置过程

vim /etc/my.cnf

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE #关闭binlog校验
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW #组复制依赖基于行的复制格式

transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="c36cc649-3f17-11e9-960e-525400cf2a01"    ##可以看/var/lib/mysql/auto.cnf
loose-group_replication_start_on_boot=off
loose-group_replication_local_address= "172.25.136.1:24901"
loose-group_replication_group_seeds= "172.25.136.1:24901,172.25.136.2:24901,172.25.136.3:24901"
loose-group_replication_bootstrap_group=off    ##插件是否自动引导,这个选项一般都要off掉,只需要由发起组复制的节点开启,并只启动一次,如果是on,下次再启动时,会生成一个同名的组,可能会发生脑裂
loose-group_replication_ip_whitelist="127.0.0.1,172.25.136.0/24"
loose-group_replication_enforce_update_everywhere_checks=ON
loose-group_replication_single_primary_mode=OFF  #后两行是开启多主模式的参数

4.启动mysqld
systemctl start mysqld
5.初始化数据库

[root@server1 mysql]# grep password /var/log/mysqld.log

2019-03-14T07:50:42.947487Z 1 [Note] A temporary password is generated for root@localhost: J)hjM=V39sw>

登录数据库,先修改密码
mysql> alter user root@localhost identified by 'Wsp+123ld';

6.配置    #看官网复制 https://dev.mysql.com/doc/refman/5.7/en/group-replication-user-credentials.html

mysql> SET SQL_LOG_BIN=0;    #关闭二进制日志,防止传到其他server上
mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'Wsp+123ld';

mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';

mysql> FLUSH PRIVILEGES;

mysql> SET SQL_LOG_BIN=1;    ##开启日志

mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='Wsp+123ld' FOR CHANNEL 'group_replication_recovery';

mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so';

mysql> SHOW PLUGINS;    ##查看插件
| group_replication          | ACTIVE   | GROUP REPLICATION  | group_replication.so | GPL     |
+----------------------------+----------+--------------------+----------------------+---------+

mysql> SET GLOBAL group_replication_bootstrap_group=ON;    ##组复制发起节点开启这个参数

mysql> START GROUP_REPLICATION;

mysql> SET GLOBAL group_replication_bootstrap_group=OFF;

mysql> SELECT * FROM performance_schema.replication_group_members;    ##查看server1是否online

注意:先不要添加数据 最后测试的时候再添加
加入数据

mysql> CREATE DATABASE test;

mysql> USE test;

mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 TEXT NOT NULL);

mysql> INSERT INTO t1 VALUES (1, 'Luis');

mysql>  SELECT * FROM t1;

添加server2到组内
server2上:

[root@server2 mysql]# systemctl stop mysqld

rm -fr /var/lib/mysql/*

vim /etc/my.cnf

server_id=2
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW

transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="c36cc649-3f17-11e9-960e-525400cf2a01" ##注意:这里和server1的保持一致!!!!!!
loose-group_replication_start_on_boot=off
loose-group_replication_local_address= "172.25.136.2:24901"
loose-group_replication_group_seeds= "172.25.136.1:24901,172.25.136.2:24901,172.25.136.3:24901"
loose-group_replication_bootstrap_group=off
loose-group_replication_ip_whitelist="127.0.0.1,172.25.136.0/24"
loose-group_replication_enforce_update_everywhere_checks=ON
loose-group_replication_single_primary_mode=OFF

#启动mysqld
systemctl start mysqld

#初始化
grep password /var/log/mysqld.log
#进入数据库

mysql> alter user root@localhost identified by 'Wsp+123ld'; #修改root用户密码

mysql> SET SQL_LOG_BIN=0;

mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'Wsp+123ld';

mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';

mysql> FLUSH PRIVILEGES;

mysql> SET SQL_LOG_BIN=1;

mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='Wsp+123ld' FOR CHANNEL 'group_replication_recovery';

mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so';

#这里不需要做server1上做的SET GLOBAL group_replication_bootstrap_group=ON;

mysql> START GROUP_REPLICATION;

'这里开启组复制可能会报错,查看mysql日志'
'cat /var/log/mysqld.log ,找到解决办法'
 

2019-03-14T08:51:52.838185Z 0 [Note] Plugin group_replication reported: 'To force this member into the group you can use the group_replication_allow_local_disjoint_gtids_join option'
mysql -pWsp+123ld

mysql> STOP GROUP_REPLICATION;

mysql> set global group_replication_allow_local_disjoint_gtids_join=on; ##直接做这一步 不用等报错

mysql> START GROUP_REPLICATION;

恢复正常

再配置server3,和server2配置相同

配置好后在server1上查看

mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 43a9e177-46c2-11e9-9b8a-52540039a8e5 | server3     |        3306 | ONLINE       |
| group_replication_applier | 926e543f-4635-11e9-bb87-525400cf2a01 | server2     |        3306 | ONLINE       |
| group_replication_applier | de5a155a-462d-11e9-b9df-5254004c61ed | server1     |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+

看到3台都是online,表示正常
这时在任何一个节点都可以看到刚才插入的数据
在任何节点写入数据,其他节点也能看到

如在server3上:
mysql> INSERT INTO t1 VALUES (2, 'wsp');

在server2和server1上查看:
mysql> select * from t1;
+----+------+
| c1 | c2   |
+----+------+
|  1 | Luis |
|  2 | wsp  |
+----+------+

可以看到刚插入的数据

发布了124 篇原创文章 · 获赞 18 · 访问量 3117

猜你喜欢

转载自blog.csdn.net/weixin_42221657/article/details/102847524