# MySQl组复制 ### 组复制部署 **环境准备** 至少需要3台服务器,每台服务器上已经完成MySQL 8.0安装 ``` 192.168.26.160 master 192.168.26.128 node1 192.168.26.130 node2 ``` 组复制可以以单主或多主模式运行,默认是单主模式,这里选取192.168.26.160(主机名master)作为单主读写服务器,其他2台为只读服务器。 **查询主库uuid** 3台机器配置文件中的uuid需要一样,在主库使用select uuid()查询,使用主库的uuid即可 ```bash mysql> select uuid(); +--------------------------------------+ | uuid() | +--------------------------------------+ | a71de24e-0bae-11f0-af42-000c29649a9e | +--------------------------------------+ 1 row in set (0.00 sec) ``` **修改配置文件** 组复制的事务传递是基于GTID的,且与部分引擎不兼容,因此需要修改相应的参数内容。 修改3台机器配置文件,新增下列参数: ```bash #----------------认证插件----------------------- #8.0默认使用的认证插件需要ssl认证,这里修改了认证插件不使用ssl default_authentication_plugin=mysql_native_password #----------------Storage_engine---------------- # 组复制的数据必须存储在事务型引擎中。在多主模式下,事务冲突监测的机制是乐观型,即先执行事务,再检测冲突。如果有冲突则所有的成员都必须回滚,因此无法执行回滚的非事务型的存储引擎和组复制不兼容,需要禁用。 disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY" #----------------Replication---------------- server_id=1 #三台机器不一样 gtid_mode=on enforce_gtid_consistency=on binlog_checksum=none log_bin=mysql-bin log_slave_updates=on binlog_format=row #----------------Group replication---------------- plugin_load_add='group_replication.so' group_replication_group_name="6afcf923-0ba5-11f0-8fad-000c29649a9e" group_replication_start_on_boot=off # 在MySQL启动时不会自动启动组复制 group_replication_local_address= "192.168.26.160:33061" #修改成每个节点的ip即可 group_replication_group_seeds= "192.168.26.160:33061, 192.168.26.128:33061, 192.168.26.130:33061" group_replication_bootstrap_group=off # 设置是否引导组服务(即创建一个组),一定要设置为off,否则每次重启都会引导一个新组出来。 ``` **重启服务** 重启服务并通过show plugins命令确认组复制插件已安装: ```bash mysql> show plugins; ``` **设置分布式恢复服务的用户凭证** 当有新成员加入组复制时,会通过分布式恢复进程(Distributed Recovery Process)来同步数据。分布式恢复进程会先找一个数据的捐赠者(Donor),并通过一个名为group_replication_reocvery的通道将捐赠者binlog中的事务发送给新成员。在这里需要一个授权用户凭证来建立分布式恢复的连接。这个用户在所有的组成员上都必须存在。 在主库执行下列命令创建连接用户: ```sql set sql_log_bin=0; create user repuser@'%' identified with 'mysql_native_password' by 'reppassword'; grant replication slave on *.* to repuser@'%'; grant connection_admin on *.* to repuser@'%'; grant backup_admin on *.* to repuser@'%'; flush privileges; set sql_log_bin=1; ``` 创建好用户后,将用户凭证指定为分布式恢复进程使用: ```sql change master to master_user='repuser', master_password='reppassword' for channel 'group_replication_recovery'; ``` **组复制引导** 第一次启动组复制称作引导,引导会创建一个组出来。通过group_replication_bootstrap_group参数来控制引导动作。引导组复制必须由单一服务器完成且只需要执行一次。如果group_replication_bootstrap_group设置为on,则每次重启都会创建出一个同名新组,这也是前面参数中将其设置为off的原因。 执行下列命令引导组复制: ```sql set global group_replication_bootstrap_group=on; start group_replication; set global group_replication_bootstrap_group=off; ``` **注意**:只有在第一次启动组复制时,才需要设置group_replication_bootstrap_group,后续成员加入时都不能设置此变量,否则会产生经典的分布式系统问题 --- 脑裂(split brain)。 一旦start group_replication;语句成功返回后,组复制就成功启动了,可以通过下列语句确认引导结果: ------------------------------------------------ ```sql select * from performance_schema.replication_group_members; ``` 查询结果显示member_state为online,member_role为primary,说明组复制已经引导成功了。 在主库运行一些事务,mysql8.0默认开始事务: ```sql create database test; use test; create table t1(id int auto_increment primary key); insert into t1 values(null); insert into t1 values(null); insert into t1 values(null); commit; ``` 然后可以通过show binlog events in '日志名';查看二进制日志中的内容,可以看到日志已写入二进制日志,此时主库可以作为捐赠者(Donor),可以将这些事务变更同步给后加入的成员。 **将其他成员加入组复制** 完成前面操作后,已经创建出了一个组,并且其中已有1台主库在运行了,下面需将另外两个成员也加入组复制。 新成员加入组时会有一个数据恢复的动作,如果加入时组内数据已经很大了,那么这个过程可能会耗费很长时间,并且如果主库purge过二进制日志,那么恢复会失败。此时应使用备份恢复工具(mysqldump/xtrabackup等)将待加入的成员数据状态还原至离主库较近的时间点,以缩短加入后的数据恢复时间。 本示例是全新环境,数据变更很少,且主库具有所有变更的日志,可以将新成员直接加入,由分布式恢复进程来同步数据。 所有从服务器重启服务并创建分布式恢复凭证 ``` set sql_log_bin=0; create user repuser@'%' identified with 'mysql_native_password' by 'reppassword'; grant replication slave on *.* to repuser@'%'; grant connection_admin on *.* to repuser@'%'; grant backup_admin on *.* to repuser@'%'; flush privileges; set sql_log_bin=1; change master to master_user='repuser', master_password='reppassword' for channel 'group_replication_recovery'; ``` 启动组复制,加入组 ```sql # 注意不需要再引导组了 mysql> start group_replication; mysql> select * from performance_schema.replication_group_members; ------+--------------+-------------+----------------+----------------------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | MEMBER_COMMUNICATION_STACK | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+ | group_replication_applier | 0a7b9277-0bab-11f0-8d9d-000c29649a9e | master | 3306 | ONLINE | PRIMARY | 8.0.41 | XCom | | group_replication_applier | aad69d1c-0bab-11f0-bee6-000c29f67e93 | node2 | 3306 | ONLINE | SECONDARY | 8.0.41 | XCom | | group_replication_applier | b0021552-0baa-11f0-bd9f-000c29b36e90 | node1 | 3306 | ONLINE | SECONDARY | 8.0.41 | XCom | +---------------------------+--------------------------------------+-------------+------- ``` 此时我们看到第二和第三个成员已经成功加入组复制,成员角色为secondary,状态为online。 ### 组复制容错测试 为了测试组复制的容错,在主库上直接杀掉MySQL进程(非正常关闭),模拟服务器宕机。 ```sql killall mysqld ``` **观察角色切换** 在原来的从库上查询成员状态(kill命令在两次查询之间执行),注意此时服务器node1的角色自动从secondary变为primay,表示其被提升为新的主库: ```sql select * from performance_schema.replication_group_members; ``` **原主库重新加入组复制** 将原主库重新启动,并加入组复制,注意此时宕机的主库将以从库的身份加入组复制(不会自动恢复主库身份),主库依然是上次切换的node1 ```sql #主库运行下列指令 start group_replication; select * from performance_schema.replication_group_members; ```