mysql复制发展历程(从5.1到8.0版本)

       mysql5.1之前的版本网上基本上都查不到什么资料了,官网上也只有5.5之后的文档。所以就从5.1开始了解复制的发展历史。

MySQL 5.1

       mysql5.1版本对于复制的新特性就是引入了基于行的复制,当服务器使用混合模式复制时,基于语句的复制是默认的,在运行时会根据具体情况动态的改变binlog格式。当使用混合模式复制时,如下几种情况会从基于语句的binlog切换到基于行:1.当函数中包含 UUID() 时。2.2个及以上包含 AUTO_INCREMENT 字段的表被更新时。3.行任何 INSERT DELAYED 语句时。4. UDF 时。5.视图中必须要求使用RBR 时,例如创建视图是使用了 UUID() 函数。

MySQL 5.5

       *mysql5.5版本引进了半同步复制,半同步复制在提交过程中增加了一个延迟,在提交事务后,只有在备库收到了该事务的二进制日志才会给客户端进行查询结束的反馈。这会给客户端查询体验增加一些延迟,不过一般不是问题,因为相对于写入硬盘的时间,通过网络传输一些日志的时延不算什么。需要注意的是半同步复制不会阻塞事务的提交,而是阻塞给客户端的反馈;当备库一直没有回应已收到事件主库会超时并转化成正常的异步复制模式。通过半同步复制可以让客户端清楚主备库上事务是否达到了一致,从而可以做出相应的应对。

       目前实现半同步复制主要有两种模式,AFTER_SYNC模式和AFTER_COMMIT模式。两种方式的主要区别在于是否在存储引擎提交后等待SlaveACK。流程图如下:

       AFTER_SYNCAFTER_COMMIT相对来讲更安全,它会在fsync binlog后直接开始对备库进行复制,而不是在commit后。考虑一种情况,在上图中第三步commit成功后,binlog还没有传给slavemaster崩溃了,此时备库会比主库少一个事务,对于其他事务来说,这个事务已经commit是可见的了,但是当切换到备库后,又发现这个事务消失了就会导致幻读。这个例子很极端,尽管对于申请这个事务的用户来说,不管是那种模式,这个事务都失败了对他没影响,但是对于其他用户的事务来说可能会出现问题。使用了AFTER_SYNC模式后,不管commit后是否crash,备库都已经收到了binlog,因而不会出现上述情况。

       不过我有个疑惑就是,如果在commit的时候crash了,但是此时binlog已经发出给备库,那么对于主库的事务这个事务不可见,但是切换到备库却又可见了,那岂不是又是幻读?

       *5.5版本还有Relay log corruption recovery特性,由relay_log_recovery参数控制,这个参数的作用是:当slave从库宕机后,假如relay-log损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的relay-log,并且重新从master上获取日志,这样就保证了relay-log的完整性。默认情况下该功能是关闭的,将relay_log_recovery的值设置为 1时,可在slave从库上开启该功能,建议开启。

       *5.5还引入了replication heartbeat特性,在master没有写binlog时发出heartbeat,以便slave知道master是否正常。取值范围:单位秒,0 4294967秒。精确度可以达到毫秒,最小的非0值是0.001秒。发出条件:master在主机binlog日志文件在设定的间隔时间内没有收到新的事件时发出。

       *5.5在多Master或环形复制的情况下,处于复制链条中间的服务器异常,可以通过

CHANGE MASTER TO MASTER_HOST=xxxIGNORE_SERVER_IDS=y跳过出问题的MySQL实例。

MySQL 5.6

       *mysql5.6开始支持多线程复制。事实上是针对每个database开启相应的独立线程,即每个库有一个单独的(sql thread).针对这样的改进,如果我们想实现多线程复制,无疑要对现存的数据库结构进行重新设计,分库分表.对于压力都集中在个别database,多线程并发复制特性就没有意义。并行复制框架实际包含了一个协调线程和若干个工作线程,协调线程负责分发和解决冲突,工作线程只负责执行。

       对于并行复制Slave必需保证回放的顺序与Master上事务执行顺序一致,因此只要做到顺序读取binlog,将不冲突的事务并发执行即可。对于库级并发而言,协调线程要保证执行同一个库的事务放在一个工作线程串行执行;对于表级并发而言,协调线程要保证同一个表的事务串行执行;对于事务级而言,则是保证操作同一行的事务串行执行。

       *支持启用GTID,在配置主从复制,传统的方式里,你需要找到binlogPOS,然后change masterto指向.mysql5.6,无须再知道binlogPOS,只需要知道masterIP/端口/账号密码即可,因为同步复制是自动的,mysql通过内部机制GTID自动找点同步。

       GTID的工作原理:1.master更新数据时,会在事务前产生GTID,一同记录到binlog日志中。2.slave端的i/o 线程将变更的binlog,写入到本地的relay log中。3.sql线程从relaylog中获取GTID,然后对比slave端的binlog是否有记录。4.如果有记录,说明该GTID的事务已经执行,slave会忽略。5.如果没有记录,slave就会从relaylog中执行该GTID的事务,并记录到binlog。由于GTID全局唯一,因而可以通过它更方便自动同步。

         MySQL通过全局变量gtid_mode控制开启/关闭GTID模式。但是gtid_mode是只读的,可添加到配置文件中,然后重启mysqld来开启GTID模式(5.7版本支持在线开启gtid)。相关配置项如下:gtid-mode = ONenforce_gtid_consistency = 1log-slave-updates   = 1log-bin = mysql-binlog-bin-index  = mysql-bin.index

       开启gtid_mode时,log-binlog-slave-updates也必须开启,否则MySQL Server拒绝启动(后面的版本有了gtid executed表持久化就不用一定开启它了)。除此以外,enforce-gtid-consistency也必须开启,否则MySQL Server也拒绝启动。enforce-gtid-consistency是因为开启grid_mode以后,许多MySQLSQLGTID是不兼容的。比如开启ROW 格式时,CREATE TABLE ... SELECT,在binlog中会形成2个不同的事务,GTID无法唯一。另外在事务中更新MyISAM表也是不允许的。

       gtid_purgedgtid_executed变量在mysql启动时初始化。MySQL在启动时打开最老的binlog文件,读取其中的Previous-GTIDs,那么就是@@global.gtid_purgedMySQL在启动时打开最新的binlog文件,读取其中的Previous-GTIDs,构造一个gtid_set,然后再遍历这个最新的binlog文件,把遇到的每个gtid都添加到gtid_set中,当文件遍历完成时,这个gtid_set就是@@global.gtid_executed

       需要注意的一个地方是当master开启一个新的从库时,通过mysqldump给从库备份需要设置gtid purged来设置复制开始的地方,因为开去master auto position后,备库会根据自己的gtid executedgtid purged发给主库来让主库判断应该从哪儿开始复制,而备库使用备份是没有gtidexecuted(不是有一个gtid executed表吗,感觉有点奇怪),所以会导致问题。

       *基于行的复制只保存改变的列,大大节省硬盘和网络资源。

       *支持把Master Slave的相关信息记录在Table,原来是记录在文件里,记录在表里,增强可用性。

       *支持延迟复制。延迟复制的应用场景有:误删除恢复,延迟测试,历史查询。

MySQL 5.7

       *mysql5.7开始支持groupreplication即组复制。mysql组复制基于paxos协议。复制组由多个 server成员构成,并且组中的每个 server 成员可以独立地执行事务。在单主模式下,组复制具有自动选主功能,每次只有一个 server成员接受更新。在多主模式下,所有的 server 成员都可以同时接受更新。但所有读写(RW)事务只有在冲突检测成功后才会提交。只读(RO)事务不需要在冲突检测,可以立即提交。换句话说,对于任何 RW 事务,提交操作并不是由始发 server 单向决定的,而是由组来决定是否提交。准确地说,在始发 server 上,当事务准备好提交时,该 server 会广播写入值(已改变的行)和对应的写入集(已更新的行的唯一标识符)。然后会为该事务建立一个全局的顺序。最终,这意味着所有 server 成员以相同的顺序接收同一组事务。因此,所有 server 成员以相同的顺序应用相同的更改,以确保组内一致。组复制能够根据在一组 server 中复制系统的状态来创建具有冗余的容错系统。因此,只要它不是全部或多数 server 发生故障,即使有一些 server 故障,系统仍然可用,最多只是性能和可伸缩性降低,但它仍然可用。server 故障是孤立并且独立的。它们由组成员服务来监控,组成员服务依赖于分布式故障检测系统,其能够在任何 server 自愿地或由于意外停止而离开组时发出信号。他们是由一个分布式恢复程序来确保当有 server 加入组时,它们会自动更新组信息到最新。并且多主更新确保了即使在单个服务器故障的情况下也不会阻止更新,不必进行 server故障转移。因此,MySQL 组复制保证数据库服务持续可用。

       组复制具有自动检测脑裂的能力,可以容忍脑裂出现的双写情况(当部分分区完全和另外一部分分区无法通信而导致的脑裂,那是怎么广播进行冲突检测的?)。

       组复制冲突检测有两个因素:事务是否修改了同样的数据(以行为单位,通过主键识别)。是否是同时修改的。通过事务执行时的数据库快照版本来判定。数据库的快照是用GTID SET来标识的。事务提交前从全局变量gtid_executed中获取GTID SET。这个GTID SET就是代表了当前事务在提交前,数据库中已经执行了的GTIDs。也即是当前事务提交前,数据库的快照版本。数据库的快照版本会随着事务的BinlogEvents一起广播到其他的节点上,用来做冲突检测。

       冲突检测时,从冲突检测数据库中找到当前事务修改的数据的记录。如果没有找到,就没有冲突。如果找到了,则将自己的快照版本和冲突检测数据库中记录的GTID SET进行比对:如果自己的快照版本中包含了冲突检测数据库中记录的所有GTIDs,那么就没有冲突。自己的快照中包含了,说明该事务在初始节点上执行时,上一次对本行数据的修改已经在初始节点上提交了。所以就不是同时执行的。如果自己的快照版本中没有包含冲突检测数据库中记录的所有GTIDs,则说明当前事务在初始节点上执行时,上一次对本行数据的修改还没有在初始节点上执行。因此判定为同时执行。

       感觉组复制的多主模式应该不适用于数据操作集中在一个库的应用,因为冲突检测可能会频繁失败导致回滚。

       *5.7版本支持在线开启gtid

       *引入slave paralleltype,通过它可以设置备库并行复制的方式,默认是database即库级别并行复制,为了配合组复制特性设置为logical clock能够更大的发挥出它的性能。并行复制的原理暂时还没学习就先不说了。

MySQL 8.0

       *最主要的性能提升是binlog引进了writeset信息。writeset本质上就是基于主键的,或者说是基于行的并发策略。如果两个事务修改了不同行的数据,由于主键不同,就可以并发执行。在有些用户场景下,我们可能会希望同一个session里面,不能做并发执行。因为可能与某些业务逻辑冲突。因此还有基于writeset的另一种机制。会判断是否是同一个session的事务。如果是同一个session的,则会进行顺序执行(应该是根据binlog信息判断是否一个session)。

       *binlog新增了部分元数据。这些元数据主要分为两类。一类是在GTID event里面增加了元数据。另一个是事务的长度,也就是事务中所包含的所有event加起来的长度。还增加了commit event中的时间戳。这里的时间错是毫秒级别的,方便我们监控数据复制的延迟。第二类是table map event主要是增加了各个字段的具体类型,有没有符号,所属的字符集,还包括列的名字,主键,枚举型和集合型的字符串的值。都会记录到元数据信息里面。这样在抽取数据的时候就可以准确地知道数据的类型,会非常方便。

       *不允许对离开组的成员进行修改。在节点离开组的时候,或者刚加入组还没有被其他节点所感知的时候,如果用户对该节点进行写入会导致问题,因而在这些时候8.0会将节点设置为super read only来防止写入。

       *通过权重来选举新的主库。用户可以通过指定组成员的权重来控制主库的选举,当现有的主节点退出组复制,权重最高的节点就会被提升为主节点。

       *增加了一些流控参数。可能因为一些意外的情况导致数据延迟,因此加入了更多的参数在里面,用户只需要对参数进行调整和配置。当集群发现存在数据不同步的现象时,会自动地做流控,从而让延迟的节点有机会能够追上其他节点。(那这样做的话岂不是牺牲了所有其他节点的一些性能,感觉有些不值得)。

       *mysql5.7版本开始发布innodb cluster作为一整套高可用框架的解决方案。集成了MGRmysql shell以及mysql router三个组件。包含了读写分离,多主写入,负载均衡,读横向扩展,写横向扩展等功能。这个应该是mysql未来发展的一个方向。

猜你喜欢

转载自blog.csdn.net/qq_38125183/article/details/80721500