1、MySQL复制的三种模式html
MySQL当前存在的三种复制模式有:异步模式、半同步模式和组复制模式,先了解一下三种模式的工做方式。mysql
异步复制是MySQL最先的也是当前使用最多的复制模式,异步复制提供了一种简单的主-从复制方法,包含一个主库(master)和备库(一个,或者多个)之间,主库执行并提交了事务,在这以后(所以才称之为异步),这些事务才在从库上从新执行一遍(基于statement)或者变动数据内容(基于row),主库不检测其从库上的同步状况。在服务器负载高、服务压力大的状况下主从产生延迟一直是其诟病。工做流程简图以下:算法
MySQL5.5的版本在一步同步的基础之上,以插件的形式实现了一个变种的同步方案,称之为半同步(semi-sync replication)。这个插件在源生的异步复制上,添加了一个同步的过程:当从库接收到了主库的变动(即事务)时,会通知主库。主库上的操做有两种:接收到这个通知之后才去commit事务;接受到以后释放session。这两种方式是由主库上的具体配置决定的。当主库收不到从库的变动通知超时时,由半同步复制自动切换到异步同步,这样就极大了保证了数据的一致性(至少一个从库),可是在性能上有所降低,特别是在网络不稳定的状况下,半同步和同步之间来回切换,对正常的业务是有影响的。其工做流程简图以下:sql
不管是异步复制仍是半同步复制,都是一个主下面一个从或是多个从的模式,在高并发下高负载下,都存在延迟状况,此时若是主节点出现异常,那么就会出现数据不一致的状况,数据可能会丢,在金融级数据库中是不能容忍的。在这种状况下,急需出现一种模式来解决这些问题。在MySQL5.7.17的版本中,带着这些期待,新的复制模式组复制产生并GA了(本文的测试等数据均基于MySQL5.7.17)。数据库
组复制的工做流程图以下:bootstrap
MySQL组复制是一个MySQL插件,它创建在现有的MySQL复制基础结构上,利用了二进制日志,基于行的日志记录和全局事务标识符等功能。它集成了当前的MySQL框架,如性能模式、插件和服务基础设施等。服务器
组复制(Group Replication)基于分布式一致性算法(Paxos协议的变体)实现,一个组容许部分节点挂掉,只要保证绝大多数节点仍然存活而且之间的通信是没有问题的,那么这个组对外仍然可以提供服务,它是一种被使用在容错系统中的技术。Group Replication(复制组)是由可以相互通讯的多个服务器(节点)组成的。在通讯层,Group replication实现了一系列的机制:好比原子消息(atomic message delivery)和全序化消息(total ordering of messages)。这些原子化,抽象化的机制,为实现更先进的数据库复制方案提供了强有力的支持。MySQL Group Replication正是基于这些技术和概念,实现了一种多主全更新的复制协议。简而言之,一个Group Replication就是一组节点,每一个节点均可以独立执行事务,而读写事务则会在于group内的其余节点进行协调以后再commit。所以,当一个事务准备提交时,会自动在group内进行原子性的广播,告知其余节点变动了什么内容/执行了什么事务。这种原子广播的方式,使得这个事务在每个节点上都保持着一样顺序。这意味着每个节点都以一样的顺序,接收到了一样的事务日志,因此每个节点以一样的顺序重演了这些事务日志,最终整个group保持了彻底一致的状态。然而,不一样的节点上执行的事务之间有可能存在资源争用。这种现象容易出如今两个不一样的并发事务上。假设在不一样的节点上有两个并发事务,更新了同一行数据,那么就会发生资源争用。面对这种状况,Group Replication断定先提交的事务为有效事务,会在整个group里面重放,后提交的事务会直接中断,或者回滚,最后丢弃掉。所以,这也是一个无共享的复制方案,每个节点都保存了完整的数据副本。网络
从其工做的原理能够看出,Group Replication基于Paxos协议的一致性算法校验事务执行是否有冲突,而后顺序执行事务,达到最终的数据一致性,也就意味着部分节点能够存在延迟。能够设置多主同时写入和单主写入,经过设置group_replication_single_primary_mode来进行控制是多主仍是单主,官方推荐单主写入,容许延迟,但延迟过大,则会触发限流规则(可配置的),整个集群会变的很慢,性能大打折扣。session
在MySQL的底层,GR增长了另外的API层来实现所须要的功能。程序结构上,GRAPI主要分为三部分:多线程
1:capture 追踪当前正在执行的事务的上下文。
2:applier 执行远程事务传输到本地的日志到本地数据库。
3:recovery 负责分布式环境下的节点恢复,以及相关的数据回追,失败处理等。
在这几个主要API层的下面,是统一的复制协议逻辑处理层,这一层主要是统一应用层的各类调用。在更下层,则是通用程度更高的分布式通信层,处于调用便利,分布式通信曾对上提供使用的API,API的下面,是Paxos实现的分布式通信协议组件,这个组件与集群中其余节点一块儿,造成一个虚拟概念化的分布式集群。
这个压缩主要是指MySQL的bin-log压缩,所使用的压缩算法是LZ4。当网络带宽是瓶颈时,消息压缩能够在组通讯级别提供高达30-40%的吞吐量改进,这在网络传输压力比较大的组中是尤其重要的。LZ4能很好的支持多线程环境,得到更高的压缩和解压速度。如下是压缩算法LZ4的压缩和解压状况:
压缩发生在组通讯引擎级别,以前数据被交给组通讯线程,因此它发生在mysql用户会话线程的上下文中。事务有效网络负载能够在被发送到组以前被压缩,而且在被接收时被解压缩。压缩是有条件的,而且取决于配置的阈值。默认状况下启用压缩,此外,它并不要求组中的全部服务器节点都启用压缩机制,在接收到消息时,成员检查消息信封以验证它是否被压缩,若是须要,则成员解压缩该事务,而后将其传递到上层。
默认状况下启用压缩,阈值为1000000字节(1MB)。压缩阈值(以字节为单位)能够设置为大于默认值。在这种状况下,只有具备大于阈值的有效负载的事务被压缩。下面是如何设置压缩阈值的示例。
STOP GROUP_REPLICATION; SET GLOBAL group_replication_compression_threshold= 2097152; START GROUP_REPLICATION;
这将压缩阈值设置为2MB。若是事务生成的有效内容大于2MB的复制消息,例如大于2MB的二进制日志事务条目,则会对其进行压缩。禁用压缩设置阈值为0。注意:修改这个阈值是须要重启组复制的。
消息压缩流程图以下:
1. 全部涉及的数据都必须发生在InnoDB存储引擎的表内。
2. 全部的表必须有明确的主键定义。
3. 网络地址只支持IPv4。
4. 须要低延迟,高带宽的网络。
5. 目前集群限制最多容许9个节点。
6. 必须启用binlog。
7. binlog 格式必须是row格式。
8. 必须打开gtid模式。
9. 复制相关信息必须使用表存储。
10.事务写集合(Transaction write set extraction)必须打开。(这个目前与savepoint冲突,这也是致使mysqldump没法备份GR实例的缘由)
11. log slave updates必须打开。
12. binlog的checksum目前不支持。
13. 因为事务写集合的干扰,没法使用savepoint。
14. SERIALIZABLE 隔离级别目前不支持。
15. 对同一个对象,在集群中不一样的实例上,并行地执行DDL(哪怕是相互冲突的DDL)是可行的,但会致使数据一致性等方面的错误,目前阶段不支持在多节点同时执行同一对象的DDL。
16. 外键的级联约束操做目前的实现并不彻底支持,不推荐使用。
依据组复制的要求和限制,如下设置根据MySQL组复制要求配置复制:
server_id = 1
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
此时my.cnf文件可确保服务器配置,并指示实例化一个给定的配置下的复制基础设施。如下部分配置服务器的组复制设置。具体参数比较简单,不在这里赘述,可参见官方说明:
transaction_write_set_extraction = XXHASH64
loose-group_replication_group_name =“aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa”
loose-group_replication_start_on_boot = off
loose-group_replication_local_address ="127.0.0.1:24901”
loose-group_replication_group_seeds =“127.0.0.1:24901,127.0.0.1:24902,127.0.0.1:24903”
loose-group_replication_bootstrap_group = off
具体的组复制安装部署比较简单,网上和官方说明都有说明,在这里就不阐述安装部署这块了。
组复制分为多主和单主两种模式,默认是单主模式,也是官方推荐的组复制模式。单个集群中不能同时使用两种模式,例如一个配置在多主模式,而另外一个在单主模式。要在模式之间切换,须要使用不一样的操做配置从新启动集群。不管部署模式如何,组复制不处理客户端故障切换,它必须由应用程序自己、链接器或中间件框架(如代理或路由器)等处理。
在此模式下,组具备设置为读写模式的单主实例,主节点一般是用于解析组的第一个服务器,组中的其余其余节点都自动设置为只读模式(即,超级只读),全部其余加入的节点自动识别主节点并设置为本身为只读。
在单主机模式下,将禁用在多主机模式下部署的某些检查,由于系统会强制每次只有一个写入节点。例如,容许对具备级联外键的表进行更改,而在多主模式下不容许。在主节点故障时,自动选举机制选择下一个主节点。经过按字典顺序(使用其UUID)并选择列表中的第一个节点来排序剩余的节点来选择下一个主节点。若是主节点从组中删除,则执行选择,并从组中的其他节点中选择新的主节点,这个选择按照词典顺序排序节点UUID并选择第一个来执行。一旦选择了新的主节点,其余节点将设置为从节点,从节点为只读。以下图:
在多主模式下,没有单个主模式的概念,也没有选举程序,由于没有节点发挥任何特殊的做用。加入组时,全部服务器都设置为读写模式。
在多主要模式下部署时,将检查语句以确保它们与模式兼容。在以多主模式部署组复制时进行如下检查:
1:若是事务在SERIALIZABLE隔离级别下执行,则在将其与组同步时,它的提交将失败。
2:若是事务对具备级联约束的外键执行,则事务在与组同步时没法提交。
这些检查可经过设置选项停用 group_replication_enforce_update_everywhere_checks 到FALSE。当在单主要方式部署,该选项必须设置为 FALSE。以下图:
目前MySQL官方没有发布链接组复制专用的客户端(如MongoDB链接复制集的客户端),在实际的应用中若是发生故障,须要客户端本身来处理。对于单主模式的话,若是主节点发生故障,客户端须要判断新的主节点是谁,而后把写切换到新的主节点,基本上和当前的异步同步的主从切换同样,而且新的主节点是集群自动产生,不可控;多主模式须要在客户端进行节点可用性检查,当其中的一个写节点不可用时自动使用其余可用节点。
在实际生产中,综合两种组复制模式的故障切换,可使用多主模式,指定其中一个节点为主节点,其余节点置为只读节点,这样主节点故障时,新的主节点可控。
目前版本测试并发进行大数据操做和DDL操做时,kill掉大事务,有概率形成集群不可用;在insert into …….select……limit……这种大事务支持很差,可能形成集群不用;多主模式进行DDL操做须要集群内全部节点都为ONLINE状态才可执行,处于ERROR和RECOVERING状态时有概率致使集群堵塞,严重时集群不可用。
在组复制集群其中的一个节点上执行数据库备份时,无论使用mysqldump(这个不能使用--single-transaction参数,生产中不建议使用mysqldump备份集群数据)或是使用xtrabackup的QPS降低40%,而且备份节点基本中止读写。在测试备份文件导入数据时,多主模式要比单主模式慢。推荐使用组复制+异步复制方式,在异步复制的从节点上进行数据库备份。
由于组复制同步仍是基于二进制日志来进行同步的,清理某个节点bin-log时,必须断定这个日志文件是否还在使用,若是在使用,则绝对不能删除,若是删除,则整个集群直接ERROR。
目前MySQL5.7.17的版本中没法直观查看节点同步延迟,也没法获取延迟多少,无论是时间或事物数,这个打开MySQL的Debug模式,能够获取到节点的延迟事务状况。
组复制的延迟对集群是有影响的,一旦出现延迟(默认延迟25000个事务),则启动流量控制(Flow Control),每一个周期性能衰减当前的10%,直到集群不可用(但集群节点状态为online),单个节点慢整个集群全慢。
集群中的每一个节点都会验证并应用该组提交的事务,有关校验和应用程序过程的统计信息对于了解应用程序队列如何增加,已找到多少冲突,检查了多少事务,在哪里提交了哪些事务等等很是有用。表 performance_schema.replication_group_member_stats 提供与事务认证过程的相关信息,但没有延迟信息。相关字段解释以下:
字段 |
描述 |
Channel_name |
组复制通道的名称。 |
Member_ID |
表明当前链接到的成员服务器UUID。组中的每一个节点具备不一样的值,是一个惟一键,由于它对每一个成员是惟一的。 |
Count_Transactions_in_queue |
队列中等待冲突检测检查的事务数。一旦检查到冲突,而且他们经过检查,他们将排队等待应用。 |
Count_transactions_checked |
表示已检查冲突的事务数。 |
Count_conflicts_detected |
表示未经过冲突检测检查的事务数。 |
Count_transactions_validating |
表示冲突检测数据库的当前大小(每一个事务通过验证的数据库)。 |
Transactions_committed_all_members |
表示已在当前视图的全部成员上成功提交的事务。这以固定的时间间隔更新。 |
Last_conflict_free_transaction |
显示最后一次无冲突校验检查的事务标识符。 |
无论是多写仍是单写,都并不是是强一致性,均容许有延迟,他在校验完事务是否冲突后把当前广播到各个节点并肯定各个节点收到事务后即进入下一个事物的冲突检测,此时每一个节点只是拿到了全部事务的执行序列,保证了事务最终顺序执行,从而保证数据的最终一致性,但同一时刻并不是强一致性的。
节点越多性能损耗越大,三个节点比较合适。节点故障可能有脑裂等问题:如5个节点分布在两个机房,机房间网络断掉分为两个部分,2个集群的机房不可用,3个节点的可用,而三个节点的机房网络有问题,此时若是想使两个节点的机房可用,须要从新对两个节点作集群重组,三个节点的就没法恢复到两个节点中去;三节点中其中一个节点宕机,其余两个正常节点可用,故障节点重启没有加入到集群时,此时这个节点以单实例存在可读写,此时会发生脑裂。
测试过程当中使用TC命令来模拟网络延迟:
tc qdisc add dev eth0 root netem delay 50ms 10ms 增长网络延迟50ms,10ms左右的浮动
tc qdisc del dev eth0 root netem delay 50ms 10ms 删除网络延迟
通过测试网络延迟对比组复制MySQL的QPS:网络延迟设置50ms和正常的对比,QPS下降至少1/3,甚至1/2,网络延迟对性能影响挺大。如下是测试状况:
MySQL官方网站提到了组复制的弹性自动扩展,通过实际测试,这种扩展在生产中是不现实的。可用于生产的弹性扩展要求新加入一个集群,集群中的数据彻底由集群来完成自动同步,但因为组复制是基于二进制日志来进行同步的,生产中是不可能完整保留所有的二进制日志,在新加入的节点须要先备份出集群的全量数据,而后根据同步位置去追事务达到数据的一致后节点状态online状态,其实和以前异步同步搭建主从同样。而且官方提示若是恢复时的延迟过大,可能也没法正常达到追到最新数据的位置。
官方说明中关于故障处理的时候有一句话:组复制不处理客户端故障切换,它必须由应用程序自己,链接器或中间件框架(如代理或路由器)处理。官方一再强调MySQL组复制提供了高可用、高弹性、可靠的MySQL服务,那么官方是否提供一套相似MongoDB复制集的客户端组件来支持那?
目前的解决方法就是和异步复制的切换差很少,使用域名切换或是本身实现一套高可用的客户端链接方式。但就目前来讲效率最高的是结合本身的业务,修改组复制故障处理的源码,当检测到写节点故障时结合本身的域名切换来处理。但这样对DBA来讲须要源码开发能力,相对要求比较高。
在单主模式下,不能直观的获取主库的IP地址,使用如下命令能够获取到主节点的UUID:
mysql> SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME ='group_replication_primary_member';
+ -------------------------------------- +
| VARIABLE_VALUE |
+ -------------------------------------- +
| 69e1a3b8-8397-11e6-8e67-bf68cbc061a4 |
+ -------------------------------------- +
1行(0,00秒)
使用SELECT * FROM performance_schema.replication_group_members能够查看到UUID对应到的MEMBER_HOST,而MEMBER_HOST指的是主机名,须要在MySQL的配置文件中指定report-host为IP地址,这样就能够两个表关联查询到主库的IP地址。
从测试的状况来看,对大事务等的支持不够,运维管理方面作的不友好,相关组复制的配套监控、客户端等不完善,有一部分问题是能够规避和曲线解决的,有一部分须要源码层面的支持;在性能上和PXC对比,要优于PXC,这个和各自的复制协议不一样分不开的。
MySQL组复制提供了高可用、高弹性、可靠的MySQL服务,旨在打造金融级MySQL集群。在忽略网络延迟的状况,能够轻松的实现多活和异地调用就近写库,这一点是业务上比较期待的。组复制是MySQL将来的一个发展趋势,相信在将来的版本中会更加的完善,期待成熟版本。
参考文档:http://dev.mysql.com/doc/refman/5.7/en/group-replication.html