组复制

2020-11-24
  1. 组复制是一个MySQL Server插件,使您可以创建弹性的,高可用性的,容错的复制拓扑。
  2. 组具有单主模式和多主模式
  3. 复制组是一组服务器,每个服务器都有自己的完整数据副本,并通过消息传递相互交互。通信层提供了一组保证,例如原子消息和总订单消息传递。
  4. 一个复制组由多个服务器组成,该组中的每个服务器可以随时独立执行事务。但是,所有读写事务只有在组批准后才提交。只读事务无需组内的任何协调即可立即提交。
  5. 当读写事务准备好在原始服务器上提交时,服务器自动广播写值(已更改的行)和相应的写集(已更新的行的唯一标识符)。因为事务是通过原子广播发送的,所以组中的所有服务器要么接收该事务,要么没有服务器接收该事务。如果它们接收到它,那么它们都按照与之前发送的其他事务相同的顺序接收它。因此,所有服务器以相同的顺序接收同一组事务,并为事务建立全局总顺序。
  6. 成员资格服务依赖于分布式故障检测器,该检测器能够在任何服务器自愿或由于意外停止而离开组时发出信号。有一个分布式恢复过程可确保当服务器加入该组时,它们将自动更新。无需服务器故障转移,并且每个副本都可以更新的多源特性确保即使是更新也不会在单个服务器故障的情况下被阻塞
  7. 在MySQL组复制中,一组服务器构成一个复制组。群组具有名称,该名称采用UUID的形式。该组是动态的,服务器可以随时离开(自愿或非自愿)并加入。每当服务器加入或离开时,该组都会进行自我调整。
  8. 有一个内置的组成员服务,它使组的视图保持一致,并且在任何给定的时间点上对所有服务器可用。服务器可以离开并加入组,视图会相应地更新。有时,服务器可能会意外地离开组,在这种情况下,故障检测机制会检测到这种情况,并通知组视图已经更改。这都是自动的。
  9. 组复制的最小实例数为3个
  10. 数据必须存储在InnoDB事务存储引擎中
  11. 每个表必须有主键或等效主键
  12. 仅支持IPv4网络
  13. 成员数量最大为9
  14. 事务以相同的顺序交付给所有组成员,但是它们的执行不同步,这意味着在接受了要提交的事务之后,每个成员都按照自己的进度进行事务。
  15. 组成员使用异步复制实现分布式恢复以跟上主数据,分布式恢复过程依赖于一个名为group_replication_recovery的复制通道,该通道用于将事务从种子成员转移到加入该组的新成员

组复制的典型用例:

  • 弹性复制:服务器的数量可以动态增加或减少,并且副作用要尽可能少。例如,用于云的数据库服务。
  • 高度可用的分片:分片是实现写入横向扩展的一种流行方法。使用MySQL组复制来实现高度可用的分片,其中每个分片都映射到一个复制组。
  • 源复制的替代方法:在某些情况下,使用单个源服务器会使它成为单个竞争点。在某些情况下,写给整个小组可能会更具扩展性。
  • 自主系统:部署MySQL组复制来实现内置到复制协议中的自动化

配置

server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
log_bin=binlog
#、组中的服务器需要记录从组接收并应用的所有事务。因为恢复是依靠组中参与者的二进制日志来进行的。因此即使不是在服务器本身上启动的那些事务,每个事务的副本也必须存在于每台服务器上。
log_slave_updates=ON
#二进制日志格式,组复制依靠基于行的复制格式在组中的服务器之间一致地传播更改。它依靠基于行的基础结构来提取必要的信息,以检测在组中的不同服务器中同时执行的事务之间的冲突
binlog_format=ROW

#组复制无法使用它们,因此必须将其禁用
binlog_checksum=NONE
#表名以小写形式存储在磁盘上,并且比较时不区分大小写,修改后需要重新引导组
lower_case_table_names = 1
#多线程的数量,允许组复制成员可以并行应用事务。
slave_parallel_workers=16
#确保并行事务的最终提交原始事务的顺序相同
slave_preserve_commit_order=1
slave_parallel_type=LOGICAL_CLOCK

#生成散列的算法,该散列标识与事务关联的写入。如果使用组复制,则哈希值用于分布式冲突检测和处理
transaction_write_set_extraction=XXHASH64
#启用组复制插件
plugin_load_add='group_replication.so'
#组复制组名,同一组成员的uuid要相同,可以SELECT UUID()用来生成UUID
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
#off指示插件在服务器启动时不自动启动操作。配置组是先设置为off,配置组后设置为on
group_replication_start_on_boot=off
#设置成员用于与组中其他成员进行内部通信的网络地址和端口,可以是IP或主机名。从MySQL 8.0.14起,可以使用IPv6地址、主机名以及IPv4地址。组可以包含使用IPv6的成员和使用IPv4的成员的混合,默认端口为33061
group_replication_local_address= "s1:33061"
#从指定组成员的hostname:port获取数据,可以选择组成员的一个子集作为种子成员,引导组的服务器不使用此选项
group_replication_group_seeds= "s1:33061,s2:33061,s3:33061"
#指示插件是否为引导组。确保只有一个成员为引导组,如果为on,那么服务器在重新启动时会自动引导另一个具有相同名称的组,这将导致两个不同的组具有相同的名称
group_replication_bootstrap_group=off
#成员的百分比权重,选择主时的优先级,多主模式不需要
group_replication_member_weight=40


#以下需要在所有组成员必须有相同配置
#高于该阈值(字节)将压缩应用于组成员之间发送的消息。0禁用压缩。使用LZ4压缩算法压缩在组中发送的消息。LZ4压缩算法支持的最大输入大小为2113929216字节。此限制低于group_replication_compression_threshold的最大值,默认值1000000
group_replication_compression_threshold = 1000000
#配置复制组接受的最大事务大小(字节),大于指定大小的事务将回滚,并且不会广播到该组。5.7默认0(不限制),8.0默认150000000字节(约143 MB)
group_replication_transaction_size_limit = 0

#以下修改设置后需要重新引导组
#自动选择主服务器,off关闭单主,启用多主
group_replication_single_primary_mode=on
#严格一致性检查,默认禁用,单主模式必须禁用,多主模式建议启用。
group_replication_enforce_update_everywhere_checks=off
#为每个成员保留的连续GTID的数量,默认1000000
group_replication_gtid_assignment_block_size=1000000
#在创建模式和常规表空间时不指定ENCRYPTION子句的情况下应用于它们的默认加密设置,仅适用于用户创建的模式和常规表空间,默认off
default_table_encryption=off

虽然group_replication_local_address设置的是IP,但是组通信时使用的主机名,所以必须为每个组成员设置不同的主机名,并且在每个组成员上配置group_replication_local_address和group_replication_group_seeds的DNS解析;或者在每个实例上配置report_host变量就可以不用配置DNS解析了;记得要开放组通信及mysql服务的端口

查看主机名
hostnamectl
配置主机名
hostnamectl set-hostname --static s1.server.com
配置DNS解析
vim /etc/hosts
192.168.11.111 s1.server.com

[mysqld]
report_host=192.168.11.128

如果主机开启了SELinux,那么还需要设置端口的上下文

getenforce
查看是否开启了SELinux Enforcing开启 Permissive警告 Disabled关闭
如果启用了SELinux需要设置TCP端口的上下文
安装管理工具
yum install semanage
如果提示No package semanage available,那么使用以下方法
yum provides semanage
yum -y install policycoreutils-python.x86_64

查看已定义上下文的端口
semanage port -l | grep mysqld

为组复制的端口添加上下文
semanage port -a -t mysqld_port_t -p tcp 33061

启动组复制

首次启动组的过程称为引导。引导程序只能由一台服务器(启动该组的服务器)执行一次,并且只能执行一次。

mysql> SET GLOBAL group_replication_bootstrap_group=ON;
mysql> START GROUP_REPLICATION;
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;

一旦START GROUP_REPLICATION 语句返回,该组已启动。您可以检查是否已创建该组,并且其中有一个成员:

mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+---------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE  |
+---------------------------+--------------------------------------+-------------+-------------+---------------+
| group_replication_applier | ce9be252-2b71-11e6-b8f4-00212844f856 |   s1        |       3306  | ONLINE        |
+---------------------------+--------------------------------------+-------------+-------------+--------

添加第二个实例

配置文件与上面的配置信息一致(除server_id,group_replication_local_address,group_replication_group_seeds)

配置恢复凭据启动组复制:因为用户在组中共享。该成员需要在“用户凭证”中配置相同的复制用户。在每个组成员上创建用户

SET SQL_LOG_BIN=0;
CREATE USER rpl_user@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
SET SQL_LOG_BIN=1;
CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='password' FOR CHANNEL 'group_replication_recovery';

START GROUP_REPLICATION;

本地部署组复制:

下载MySQL Server并将其解压缩到名为mysql-5.7的目录中
每个MySQL服务器实例都需要一个特定的数据目录。创建一个名为的目录data,然后在该目录中为每个服务器实例(例如s1,s2和s3)创建一个子目录,并初始化每个目录。

mysql-5.7/bin/mysqld --initialize-insecure --basedir=$PWD/mysql-5.7 --datadir=$PWD/data/s1
mysql-5.7/bin/mysqld --initialize-insecure --basedir=$PWD/mysql-5.7 --datadir=$PWD/data/s2
mysql-5.7/bin/mysqld --initialize-insecure --basedir=$PWD/mysql-5.7 --datadir=$PWD/data/s3

组监视

性能架构表监视组复制:

提供了与认证过程相关的组级别信息,还提供了复制组的每个单独成员接收和发起的事务的统计信息。该信息在复制组的所有服务器之间共享,可以从任何成员查询所有组成员的信息。假设与其他成员相比,该组的成员之一始终在其队列中报告大量事务。这意味着该成员被延迟,无法与该组的其他成员保持最新。根据此信息,您可以决定从该组中删除该成员,或延迟对该组其他成员的事务处理,以减少排队的事务数。

select * from performance_schema.replication_group_member_stats

用于监视该组成员的不同服务器实例的状态。只要有视图更改,表中的信息就会更新。该信息在属于复制组的所有服务器实例之间共享,因此可以从任何成员查询有关所有组成员的信息。

select * from performance_schema.replication_group_members;

/*
ONLINE:该成员随时可以充当功能齐全的组成员,这意味着客户端可以连接并开始执行事务。是组同步的
RECOVERING:该成员正在成为该组的活跃成员,并且正在接受恢复过程,正在从捐助者那里接收状态信息。不是组同步的
OFFLINE:插件已加载,但成员不属于任何组。不是组同步的
ERROR:每当恢复阶段发生错误或应用更改时,服务器就会进入此状态,进入此状态后super_read_only选项将设置为ON,要退出必须手动配置super_read_only=OFF。不是组同步的
UNREACHABLE:每当本地故障检测器怀疑给定服务器无法访问时(例如由于非自愿断开连接),它将显示该服务器的状态为UNREACHABLE。不是组同步的
*/

显示有关组复制的信息,例如,已从组接收并在申请者队列(中继日志)中排队的事务。

select * from performance_schema.replication_connection_status

显示与组复制相关的通道和线程的状态。如果有许多不同的工作线程在应用事务,那么工作表也可以用来监视每个工作线程在做什么。

select * from performance_schema.replication_applier_status

模式

单主模式(默认):
组中的所有其他成员都设置为只读模式。这会自动发生。主服务器通常是引导该组的第一台服务器,所有其他加入的服务器会自动了解主服务器,并设置为只读。
当主要成员失败时,自动的主要选举机制将选择新的主要成员
设该组的所有成员都运行相同的MySQL版本,则该成员具有最高group_replication_member_weight值被选为新的主要。如果多个服务器具有相同 group_replication_member_weight的服务器,则将根据服务器的server_uuid字典顺序对其进行优先级排序,并选择第一个服务器。
查找主数据库

SHOW STATUS LIKE 'group_replication_primary_member'

多主要模式:
加入组时,所有服务器均设置为读写模式。
如果在SERIALIZABLE隔离级别下执行事务,则在与组同步时,其提交将失败。
如果事务是针对具有具有级联约束的外键的表执行的,则该事务在与组同步时将无法提交。

恢复失败的成员

将其他主机的备份在失败的主机上恢复(如果使用物理恢复,那么要保留失败主机上的auto.cnf,已保留里面的server_uuid),恢复后重新启动组复制

恢复失败的成员重新加入组,使用mysql客户端连接到已还原的服务器, 重置源和副本信息,然后配置组复制凭据,启动组复制

mysql> RESET MASTER;
mysql> RESET SLAVE ALL;

mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='password' FOR CHANNEL 'group_replication_recovery';

mysql> START GROUP_REPLICATION;

如果要还原的成员是该组中的主要成员,在启动还原的服务器之前配置以下选项。为避免在组复制恢复阶段客户端写入数据到正在还原的数据库

将MySql服务设置为只读,并且关闭事件计划程序
group_replication_start_on_boot=OFF
super_read_only=ON
event_scheduler=OFF

还原完成后修改配置并重启MySql服务
group_replication_start_on_boot=ON
super_read_only=OFF
event_scheduler=ON

成员恢复设置

恢复数据传输依赖于二进制日志和现有的MySQL复制框架,因此,某些临时错误可能会导致接收方或应用线程中的错误。在这种情况下,供体成员切换过程具有重试功能,类似于常规复制中的功能。

当服务器试图从成员池连接到一个供体成员时,加入该组的尝试次数为10次
mysql> SET GLOBAL group_replication_recovery_retry_count= 10;
在供体成员尝试连接恢复进程之间应该休眠多少时间。默认值为60秒
mysql> SET GLOBAL group_replication_recovery_reconnect_interval= 120;

注意,恢复并不会在每次捐赠者连接尝试后停止。由于加入组的服务器不断地连接到不同的服务器,而不是同一个服务器,因此可以假定影响服务器A的问题不会影响服务器b。因此,只有在经过所有可能的提供者之后,恢复才会暂停。一旦加入组的服务器尝试连接到组中所有合适的提供者并且没有剩余,恢复进程就会休眠几秒

安全配置

白名单

group_replication_ip_whitelist:只允许指定IP的成员加入到组中
如果服务器是复制组的活动成员,则无法在服务器上更改其许可列表。如果该成员处于活动状态,则必须先STOP GROUP_REPLICATION 在更改允许列表

mysql> STOP GROUP_REPLICATION;
mysql> SET GLOBAL group_replication_ip_whitelist="192.0.2.21/24,198.51.100.44,203.0.113.0/24,example.org,www.example.com/24";
mysql> START GROUP_REPLICATION;

允许列表必须包含每个成员的group_replication_local_address指定的IP地址或主机名,可以根据您的安全要求在不同的组成员上配置不同的允许列表,以使不同的子网分开。如果需要配置其他允许列表以满足您的安全要求,请确保复制组中的允许列表之间有足够的重叠,以最大程度地提高服务器在没有原始种子成员的情况下能够重新连接的可能性。

使用SSL保护组通信连接和恢复连接

donor> SET SQL_LOG_BIN=0;
donor> CREATE USER 'rec_ssl_user'@'%' REQUIRE SSL;
donor> GRANT replication slave ON *.* TO 'rec_ssl_user'@'%';
donor> SET SQL_LOG_BIN=1;

将加入组的服务器配置为在连接到主服务器时使用这些凭据。这是根据为组复制插件提供的SSL选项的值完成的。配置恢复通道以使用需要SSL连接的用户的凭据

new_member> SET GLOBAL group_replication_recovery_use_ssl=1;
new_member> SET GLOBAL group_replication_recovery_ssl_ca= '.../cacert.pem';
new_member> SET GLOBAL group_replication_recovery_ssl_cert= '.../client-cert.pem';
new_member> SET GLOBAL group_replication_recovery_ssl_key= '.../client-key.pem';

new_member> CHANGE MASTER TO MASTER_USER="rec_ssl_user" FOR CHANNEL "group_replication_recovery";
new_member> START GROUP_REPLICATION;

可以在my.cnf中配置

[mysqld]
#具有受信任的SSL证书颁发机构的文件的路径
ssl_ca = "cacert.pem"
#包含受信任的SSL证书颁发机构的证书的目录路径
ssl_capath = "/.../ca_directory"
#证书文件的路径。用作客户端和服务器证书
ssl_cert = "server-cert.pem"
#在通过连接加密数据时使用的允许密码
ssl_cipher = "DHE-RSA-AEs256-SHA"
#包含证书吊销列表的文件的路径
ssl_crl = "crl-server-revoked.crl"
#包含已撤销证书列表的目录路径
ssl_crlpath = "/.../crl_directory"
#密钥文件的路径。用作客户端和服务器证书
ssl_key = "server-key.pem"
group_replication_ssl_mode= REQUIRED

限制

  • 在故障转移事件期间,针对多主要模式组描述的限制和问题也可以适用于单主要模式集群,而新选举的主要对象会从旧的主要对象中清除其申请者队列。
  • 组复制的并发事务认证过程未考虑间隙锁(对于处于多主模式的组,除非您依赖REPEATABLE READ应用程序中的语义,否则 建议将 READ COMMITTED隔离级别与组复制一起使用)
  • 表锁和命名锁。  认证过程未考虑表锁
  • 复制事件校验和。  由于复制事件校验和的设计限制,组复制当前无法使用它们。因此设置 --binlog-checksum=NONE。
  • 可隔离的隔离级别。  多主要组中不支持SERIALIZABLE隔离级别。组复制配置为SERIALIZABLE事务隔离级别将拒绝提交事务。
  • 并行DDL与DML操作。  使用多主模式时,不支持针对同一对象但在不同服务器上执行的并发数据定义语句和数据操作语句。在对象上执行数据定义语言(DDL)语句期间,在同一对象上但在不同服务器实例上执行并发数据操作语言(DML)可能会导致未检测到在不同实例上执行的DDL冲突的风险。
  • 具有级联约束的外键。  多主模式组不支持具有多级外键依赖关系的表,特别是定义了 CASCADING 外键约束的表。这是因为导致由多主模式组执行级联操作的外键约束可能导致无法检测到的冲突,并导致该组成员之间的数据不一致。因此,我们建议group_replication_enforce_update_everywhere_checks=ON 在多主要模式组中使用的服务器实例上进行设置 ,以避免未检测到的冲突。在单主模式下,这不是问题,因为它不允许同时写入组中的多个成员,因此不存在未检测到冲突的风险。
  • 多主模式死锁。  当组以多主模式运行时, SELECT .. FOR UPDATE语句可能导致死锁。这是因为该锁未在组的成员之间共享,因此可能无法达到此类声明的期望。
  • 复制过滤器。  复制过滤器不能用于配置为组复制的MySQL服务器实例上,因为在某些服务器上过滤事务将使组无法在一致状态下达成协议。
  • 如果单个事务产生的消息内容足够大,以致于无法在5秒的时间内通过网络在组成员之间复制消息,则可能会怀疑成员失败了,然后将其驱逐出局,只是因为他们正在忙于处理消息。交易。大型事务还会由于内存分配问题而导致系统变慢。为避免这些问题,请使用以下缓解措施:
    • 尽可能尝试限制事务大小
    • 使用系统变量 group_replication_transaction_size_limit 来指定组接受的最大事务大小。在MySQL 5.7中,此系统变量默认为零,但在MySQL 8.0中,其默认最大事务大小为150000000字节(约143 MB)。
    • 使用系统变量 group_replication_compression_threshold 来指定压缩的消息大小。该系统变量的默认值为1000000字节(1 MB),因此会自动压缩大消息

命令

安装插件
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
{/if}