1.MySQL复制的三种模式MySQL目前有三种复制模式:异步模式、半同步模式和组复制模式。首先我们来了解一下三种模式的工作方式。一、MySQL异步复制(AsynchronousReplication)异步复制是MySQL最早也是目前使用最多的复制方式。异步复制提供了一种简单的主从复制方式,包括一个主库(master)和一个备库(一个,或者多个),主库执行并提交事务,之后(所以叫异步),这些事务在从库上重新执行(基于语句)或改变数据内容(基于行),主库不检测其从库上的同步。在服务器负载高、服务压力大的情况下,主从延迟一直是它的诟病。工作流程图如下:二、MySQLSemisynchronousReplication(半同步复制)MySQL5.5版本在一步同步的基础上,以插件的形式实现了一种变体同步方案,称为半同步(semi-同步)复制)。这个插件在原来的异步复制的基础上增加了一个同步过程:当从库收到主库的变化(也就是事务)时,会通知主库。对主库有两种操作:收到通知后提交事务;收到后释放会话。这两种方式由主库上的具体配置决定。当主库没有收到从库的变更通知时,会自动从半同步复制切换到异步同步,极大的保证了数据的一致性(至少一个从库),但是性能有所下降,尤其是当网络不稳定,在半同步和同步之间来回切换,会对正常业务产生影响。其工作流程图如下:3.组复制(GroupReplication),不管是异步复制还是半同步复制,都是一个slave或者一个master下多个slave的模式,高并发和高下都有延迟load这个时候如果master节点出现异常,那么就会出现数据不一致,数据可能会丢失,这在金融级数据库中是不能容忍的。在这种情况下,迫切需要一种模型来解决这些问题。在MySQL5.7.17版本中,带着这些期待,产生了新的复制模式groupreplication并GA(本文测试等数据均基于MySQL5.7.17)。GroupReplication的工作流程图如下:2.GroupReplication的工作原理MySQLGroupReplication是一个MySQL插件,它建立在现有的MySQL复制基础设施之上,利用二进制日志、基于行的日志记录和全局事务标识符和其他功能。它集成了当前MySQL框架,如性能架构、插件和服务基础设施等。组复制(GroupReplication)是基于分布式共识算法(Paxos协议的一种变体)实现的。一个组允许一些节点挂掉。只要绝大多数节点还活着,它们之间的通信没有问题,那么这个群体仍然可以对外提供服务。它是一种用于容错系统的技术。GroupReplication(复制组)由多个可以相互通信的服务器(节点)组成。在通信层,GroupReplication实现了一系列机制:如消息的原子传递、消息的全序等。这些原子和抽象机制为实现更高级的数据库复制方案提供了强有力的支持。基于这些技术和理念,MySQLGroupReplication实现了多主全更新复制协议。简而言之,一个GroupReplication就是一组节点,每个节点都可以独立执行事务,读写事务会在组内其他节点协调后提交。因此,当一个交易准备好提交时,它会自动在组内以原子方式广播,通知其他节点有什么内容被改变了/什么交易被执行了。这种原子广播方法使事务在每个节点上保持相同的顺序。这意味着每个节点都以相同的顺序接收到相同的事务日志,因此每个节点都以相同的顺序重放这些事务日志,最终整个组保持完全一致的状态。但是,在不同节点上执行的事务之间可能存在资源争用。这种现象很容易出现在两个不同的并发事务上。假设不同节点上有两个并发事务更新同一行数据,那么就会发生资源争用。面对这种情况,GroupReplication判断先提交的事务是有效事务,会在整个组中重放,而后提交的事务则直接中断,或者回滚,最后丢弃。因此,这也是一种无共享复制方案,每个节点都保留一份完整的数据副本。从其工作原理可以看出,GroupReplication是基于Paxos协议的共识算法检查事务执行是否存在冲突,然后顺序执行事务以达到最终的数据一致性,这意味着部分节点可能存在延迟。可以设置多主同时写入和单主写入。可以通过设置group_replication_single_primary_mode来控制是multi-master还是single-master。官方推荐单主写作。延迟是允许的,但是如果延迟过大,就会触发限流规则(可配置),整个集群会变得很慢,性能会大大降低。3、组复制的程序结构在MySQL的底层,GR又增加了一个API层来实现需要的功能。在程序结构上,GRAPI主要分为三个部分:1:捕获跟踪当前正在执行的事务的上下文。2:applier执行远程事务传输本地日志到本地数据库。3:recovery负责分布式环境下的节点恢复,以及相关的数据恢复、故障处理等。在这些主要的API层下面是一个统一的复制协议逻辑处理层,主要统一应用层的各种调用。在下层,它是通用性更高的分布式通信层。打电话很方便。分布式通信为上层提供了API。API下面是Paxos实现的分布式通信协议组件。该组件与集群中的其他节点一起构成了一个虚拟概念化的分布式集群。4.消息压缩(MessageCompression)这种压缩主要是指MySQL的bin-log压缩,使用的压缩算法是LZ4。当网络带宽成为瓶颈时,消息压缩可以在群组通信层面提供高达30-40%的吞吐量提升,这在网络传输压力较大的群组中尤为重要。LZ4可以很好的支持多线程环境,获得更高的压缩和解压速度。以下是使用压缩算法LZ4进行压缩和解压缩时发生的情况:压缩发生在组通信引擎级别,在数据被移交给组通信线程之前,因此它发生在mysql用户会话线程的上下文中。交易有效载荷可以在发送到组之前进行压缩,并在接收时解压缩。压缩是有条件的,取决于配置的阈值。默认情况下启用压缩。此外,它不需要组中的所有服务器节点都启用压缩机制。收到消息后,成员检查消息信封以验证它是否已压缩。如有必要,会员解压交易。然后传给上层。默认情况下启用压缩,阈值为1000000字节(1MB)。压缩阈值(以字节为单位)可以设置为大于默认值。在这种情况下,只有有效负载大于阈值的事务才会被压缩。下面是如何设置压缩阈值的示例。STOPGROUP_REPLICATION;SETGLOBALgroup_replication_compression_threshold=2097152;STARTGROUP_REPLICATION;这会将压缩阈值设置为2MB。如果事务生成的复制消息的负载大于2MB,例如大于2MB的二进制日志事务条目,它将被压缩。要禁用压缩,请将阈值设置为0。注意:修改此阈值需要重新启动组复制。消息压缩流程图如下:五、组复制的要求和限制1.限制和要求所有涉及的数据都必须出现在InnoDB存储引擎的表中。所有表都必须有明确的主键定义。网络地址仅支持IPv4。需要低延迟、高带宽的网络。当前集群限制最多允许9个节点。必须启用二进制日志。binlog格式必须是行格式。必须打开gtid模式。复制相关信息必须使用表存储。必须打开事务写集提取。(这个目前和savepoint有冲突,这就是mysqldump不能备份GR实例的原因)必须开启logslaveupdates。目前不支持binlog的checksum。由于会干扰事务写入集,因此无法使用保存点。目前不支持SERIALIZABLE隔离级别。对于同一个对象,在集群的不同实例上并行执行DDL(甚至是冲突的DDL)是可行的,但是会导致数据一致性等方面的错误。目前不支持在多个节点上同时执行同一个DDL。对象的DDL。目前对外键的级联约束操作的实现还没有完全支持,不推荐。2、组复制的相关配置以组复制的要求和限制为准。根据MySQL组复制的要求配置如下设置:1server_id=1gtid_mode=ONenforce_gtid_consistency=ONmaster_info_repository=TABLErelay_log_info_repository=TABLEbinlog_checksum=NONElog_slave_updates=ONlog_bin=binlogbinlog_format=ROWnowmy.cn可以确保服务器配置和直接实例化复制基础设施给定的配置。ThefollowingsectionsconfiguretheGroupReplicationsettingsfortheserver.具体参数比较简单,不在这里赘述,可参见官方说明:transaction_write_set_extraction=XXHASH64loose-group_replication_group_name=“aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa”loose-group_replication_start_on_boot=offloose-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=offgroupreplication具体安装部署比较简单,有网上的说明和官方说明,安装部署这里就不多说了。up.6.Multi-PrimaryorSingle-PrimaryMode(多主或单主模式)组复制分为两种模式:multi-primary和single-primary,默认是single-primary模式,也是官方推荐的groupreplication模式,两种模式不能在单个集群中同时使用,比如一个con以多主模式计算,另一个以单主模式计算。要在模式之间切换,需要使用不同的操作配置重新启动集群。无论采用哪种部署模式,GroupReplication都不会处理客户端故障转移,它必须由应用程序本身、连接器或代理或路由器等中间件框架来处理。1.单主模式该模式下,组内有一个单主实例设置为读写模式,主节点通常是第一个用来解析组的服务器,组内其他节点自动设置为只读模式(即超级只读),所有其他加入节点自动识别主节点并将自己设置为只读。在单主模式下,一些在多主模式下部署的检查被禁用,因为系统一次只强制执行一个写节点。例如,允许更改具有级联外键的表,但不允许在多主模式下进行。当主节点失效时,自动选举机制选出下一个主节点。通过按字典顺序(使用它们的UUID)对剩余节点进行排序并选择列表中的第一个节点来选择下一个主节点。如果从组中删除主节点,则执行选择并从组中的剩余节点中选择一个新的主节点,此选择将??节点UUID按字典顺序排序并选择第一个执行。一旦选举出新的主节点,其他节点将被设置为从节点,从节点是只读的。如下图所示:2.多主模式在多主模式下,没有单主模式的概念,也没有选举过程,因为没有节点扮演任何特殊角色。加入组时,所有服务器都设置为读写模式。当以多主模式部署时,将检查语句以确保它们与该模式兼容。在多主模式下部署GroupReplication时会做如下检查:1:如果一个事务是在SERIALIZABLE隔离级别下执行的,那么它在与group同步时commit会失败。2:如果事务在具有级联约束的外键上执行,事务在与组同步时无法提交。可以通过将选项group_replication_enforce_update_everywhere_checks设置为FALSE来禁用这些检查。当以单主模式部署时,此选项必须设置为FALSE。如下图所示:七、运维相关问题1、Failover问题目前MySQL官方并没有发布连接组复制的专用客户端(比如MongoDB连接复制集的客户端)。在实际应用中,如果出现故障,需要客户端来处理。对于单主模式,如果主节点发生故障,客户端需要判断新的主节点是谁,然后将写入切换到新的主节点上,这与目前的异步主从切换基本相同,并且新的主节点由集群自动生成,无法控制;多主模式需要在客户端进行节点可用性检查,当其中一个写入节点不可用时,会自动使用其他可用节点。在实际生产中,结合两种组复制模式的故障转移,可以采用多主模式,指定其中一个节点为主节点,其他节点设置为只读节点,这样当主节点失败,可以控制新的主节点。2.大额交易支持问题。当前版本测试并发大数据操作和DDL操作时,kill大事务可能会导致集群不可用;insertinto....select...limit...这种大事务支持不好,可能导致集群无法使用;多主模式下的DDL操作需要集群中所有节点都处于ONLINE状态才能执行。当处于ERROR和RECOVERING状态时,集群可能被阻塞,严重时集群不可用。3.备份问题在组复制集群中的其中一个节点上进行数据库备份时,无论使用mysqldump(这个不能使用--single-transaction参数,不建议在生产中使用mysqldump来备份集群数据)或者使用xtrabackup,QPS下降40%,备份节点基本停止读写。测试备份文件导入数据时,多主模式比单主模式慢。推荐使用组复制+异步复制的方式在异步复制的从节点上进行数据库备份。4.二进制日志删除问题由于组复制同步仍然是基于二进制日志,所以在清除某个节点的bin-log时,必须判断该日志文件是否还在使用中。如果正在使用,则不得删除。如果删除,则整个集群直接ERROR。5、同步延迟问题目前MySQL5.7.17版本无法直观查看节点同步延迟,也无法获取延迟,无论是时间还是事务数。这使得MySQL的Debug模式能够获取节点的延迟事务状态。组复制的延迟对集群有影响。一旦发生延迟(默认延迟25000个事务),启动流量控制(FlowControl),每个周期性能衰减10%,直到集群不可用(但集群节点状态在线),单个节点很慢,整个集群都很慢。集群中的每个节点都验证并应用已提交的事务集,有关校验和应用程序进程的统计信息对于了解应用程序队列如何增长、发现了多少冲突、检查了多少事务以及哪些事务在何处提交至关重要等待非常有用。表performance_schema.replication_group_member_stats提供了与事务认证过程相关的信息,但没有延迟信息。相关字段解释如下:6、数据一致性,无论是多写还是单写,都不是强一致性,允许有延迟。检查交易是否冲突后,将当前数据广播给各个节点,并对各个节点进行判断。收到交易后,会进入接下来事物的冲突检测。此时每个节点只得到所有交易的执行顺序,保证了交易最终的顺序执行,从而保证了数据的最终一致性,但同时并不是强一致性。7.节点故障和裂脑问题节点越多,性能损失越大。三个节点比较合适。节点故障可能会导致脑裂等问题:比如5个节点分布在两个机房,机房的网络坏了分成两部分。两个集群机房不可用,三个节点可用。网络有问题。这时候如果想让两个节点的机房可用,就需要重组两个节点的集群。三个节点不能恢复到两个节点;三个节点其中一个宕机,另外两个正常节点可用,故障节点重启不加入集群。这个时候这个节点是作为单实例存在的,可以读写。这时候就会出现脑裂。8、测试网络延迟问题时,使用TC命令模拟网络延迟:tcqdiscadddeveth0rootnetemdelay50ms10ms增加网络延迟50ms,浮动10ms左右tcqdiscdeldeveth0rootnetemdelay50ms10ms删除测试后网络延迟网络延迟对比组复制MySQLQPS:与正常网络延迟设置50ms相比,QPS至少降低1/3,甚至1/2,网络延迟对性能影响很大。以下是测试情况:9、弹性扩容问题MySQL官网提到组复制的弹性自动扩容。经过实际测试,这种扩展在生产中是不现实的。可以在生产中使用的弹性扩展需要添加一个新的集群。集群中的数据完全由集群自动同步。但是,由于组复制是基于二进制日志进行同步的,所以在生产中不可能完全保留所有的二进制日志。新加入的节点需要先备份集群中的全量数据,然后根据同步位置跟随事务,实现数据的一致性。节点状态在线后,其实和之前的异步同步建立主从是一样的。并且官方提醒,如果recovery的延迟过大,可能无法正常赶上***数据所在的位置。10、客户端连接问题官方描述中有一句话是关于故障排除的:GroupReplication不处理客户端故障转移,必须由应用程序本身、连接器或中间件框架(如代理或路由器)处理。官方多次强调,MySQL组复制提供高可用、高弹性、可靠的MySQL服务。官方有没有提供一套类似于MongoDB复制集的客户端组件来支持呢?目前的解决方案类似于异步复制的切换。使用域名切换或者自己实现高可用的客户端连接方式。但目前最高效的还是结合自己的业务,修改组复制故障处理的源码,结合自己的域名切换,在检测到写节点故障时进行处理。但是这对DBA的源码开发能力要求比较高。11、查找主节点的IP地址在单主模式下,无法直观的获取到主数据库的IP地址。使用以下命令获取主节点的UUID:mysql>SELECTVARIABLE_VALUEFROMperformance_schema.global_statusWHEREVARIABLE_NAME='group_replication_primary_member';+------------------------------------+|VARIABLE_VALUE|+-----------------------------------+|69e1a3b8-8397-11e6-8e67-bf68cbc061a4|+------------------------------------+1行(0,00秒)使用SELECT*FROMperformance_schema.replication_group_members查看对应的UUIDMEMBER_HOST,MEMBER_HOST指的是主机名,需要在report-host中指定IP地址mysql配置文件,这样就可以通过关联两张表来查询主库的IP地址。8、小结从测试情况来看,对大事务的支持不够,运维管理不够友好,相关组复制的监控和客户端支持不够完善。有些问题可以通过曲线来避免和解决,有些问题需要在源代码层面进行支持;与PXC相比,在性能上,它们都优于PXC,这与它们各自复制协议的不同是分不开的。MySQLGroupReplication提供高可用、高弹性、高可靠的MySQL服务,旨在打造金融级MySQL集群。在忽略网络延迟的情况下,很容易实现多活异地调用就近写库,这在业务上更值得期待。组复制是MySQL未来的一个发展趋势。相信在以后的版本中会更加完善,期待成熟的版本。参考文档:http://dev.mysql.com/doc/refman/5.7/en/group-replication.html【本文为专栏作者“王薇”原创稿件,转载请联系原作者】点击在这里可以看到作者更多的好文章
