今天咱们聊聊复制,复制对于mysql的重要性不言而喻,mysql集群的负载均衡,读写分离和高可用都是基于复制实现。下文主要从4个方面展开,mysql的异步复制,半同步复制和并行复制,最后会简单聊下第三方复制工具。因为生产环境中,innodb存储引擎支持事务,而且行级复制使用普遍,因此下文的讨论都是基于这种假设。mysql
异步复制sql
异步复制是mysql自带的最原始的复制方式,主库和备库成功创建起复制关系后,在备库上会有一个IO线程去主库拉取binlog,并将binlog写到本地,就是图1中的Relay log,而后备库会开启另一个SQL线程去读取回放Relay log,经过这种方式达到Master-Slave数据同步的目的。一般状况下,Slave是只读的,能够承担一部分读流量,并且能够根据实际须要,添加一个或多个Slave,这样在必定程度上能够缓解主库的读压力;另外一方面,若Master出现异常(crash,硬件故障等),没法对外提供服务,此时Slave能够承担起Master的重任,避免了单点的产生,因此复制就是为容灾和提升性能而生。数据库
图1网络
半同步复制并发
通常状况下,异步复制就已经足够应付了,但因为是异步复制,备库极有多是落后于主库,特别是极端状况下,咱们没法保证主备数据是严格一致的(即便咱们观察到Seconds Behind Master 这个值为0)。好比,当用户发起commit命令时,Master并不关心Slave的执行状态,执行成功后,当即返回给用户。试想下,若一个事务提交后,Master成功返回给用户后crash,这个事务的binlog还没来得及传递到Slave,那么Slave相对于Master而言就少了一个事务,此时主备就不一致了。对于要求强一致的业务是不能够接受的,半同步复制就是为了解决数据一致性而产生的。负载均衡
为何叫半同步复制?先说说同步复制,所谓同步复制就是一个事务在Master和Slave都执行后,才返回给用户执行成功。而半同步复制不要求Slave执行,而仅仅是接收到日志后,就通知Master能够返回了。这里关键点是Slave接受日志后是否执行,若执行后才通知Master则是同步复制,若仅仅是接受日志成功,则是半同步复制。对于Mysql而言,咱们谈到的日志都是binlog,对于其余的关系型数据库多是redo log或其余日志。 框架
半同步复制如何实现?半同步复制实现的关键点是Master对于事务提交过程特殊处理。目前实现半同步复制主要有两种模式,AFTER_SYNC模式和AFTER_COMMIT模式。两种方式的主要区别在因而否在存储引擎提交后等待Slave的ACK。先来看看AFTER_COMMIT模式,如图2,Start和End分别表示用户发起Commit命令和Master返回给用户的时间点,中间部分就是整个Commit过程Master和Slave作的事情。异步
图2工具
Master提交时,会首先将该事务的redo log刷入磁盘,而后将事务的binlog刷入磁盘(这里其实还涉及到两阶段提交的问题,这里不展开讲),而后进入innodb commit流程,这个步骤主要是释放锁,标记事务为提交状态(其余用户能够看到该事务的更新),这个过程完成后,等待Slave发送的ACK消息,等到Slave的响应后,Master才成功返回给用户。看到图中红色虚线部分,这段是Master和Slave的同步逻辑,是Master-Slave一致性的保证。性能
半同步复制是否能保证不丢数据?咱们经过几种场景来简单分析下。第一种状况:假设Master第1,2步执行成功后,binlog还没来得及传递给Slave,此时Master挂了,Slave做为新Master提供服务,那么备库比主库要少一个事务(由于主库的redo 和binlog已经落盘),可是不影响用户,对于用户而言,这个事务没有成功返回,那么提交与否,用户均可以接受,用户必定会进行异常捕获而重试。第二种状况,假设第3步innodb commit执行成功后,binlog还没来得及传递给Slave,此时Master挂了,此时与第一种状况同样,备库比主库少一个事务,可是其余用户在3执行完后,能够看到该事务的更新,而切换到备库后,却发现再次读这个更新又没了,这个就发生了“幻读”,若是其余事务依赖于这个更新,则会对业务逻辑产生影响。固然这仅仅是极端状况。
对于第二种状况产生的影响,AFTER_SYNC模式能够解决这一问题。与AFTER_COMMIT相比,master在AFTER_SYNC模式下,Fsync binlog后,就开始等待SLAVE同步。那么在进行第5步innodbcommit后,即其它事务能看到该事务的更新时,Slave已经成功接收到binlog,即便发生切换,Slave拥有与Master一样的数据,不会发生“幻读”现象。可是对于上面描述的第一种状况,结果是同样的。
因此,在极端状况下,半同步复制的Master-Slave会有一个事务不一致,可是对于用户而言,因为这个事务并无成功返回给用户,因此不管事务提交与否都是能够接受的,用户有必要进行查询或重试,判读是否更新成功。或者咱们想一想,对于单机而言,若事务执行成功后,返回给用户时,网络断了,用户也是面临同样的问题,因此,这不是半同步复制的问题。对于提交返回成功的事务,版同步复制保证Master-Slave必定是一致的,从这个角度来看,半同步复制不会丢数据,能够保证Master-Slave的强一致性。图3是AFTER_SYNC模式,事务提交过程。
图3
并行复制
半同步复制解决了Master-Slave的强一致问题,那么性能问题呢?从图1中能够看到参与复制的主要有两个线程:IO线程和SQL线程,分别用于拉取和回放binlog。对于Slave而言,全部拉取和解析binlog的动做都是串行的,相对于Master并发处理用户请求,在高负载下, 若Master产生binlog的速度超过Slave消费binlog的速度,致使Slave出现延迟。如图4,能够看到,Users和Master之间的管道远远大于Master和Slave之间的管道。
图4
那么如何并行化,并行IO线程,仍是并行SQL线程?其实两方面均可以并行,可是并行SQL线程的收益更大,由于SQL线程作的事情更多(解析,执行)。并行IO线程,能够将从Master拉取和写Relay log分为两个线程;并行SQL线程则能够根据须要作到库级并行,表级并行,事务级并行。库级并行在mysql官方版本5.6已经实现。如图5,并行复制框架实际包含了一个协调线程和若干个工做线程,协调线程负责分发和解决冲突,工做线程只负责执行。图中,DB1,DB2和DB3的事务就能够并发执行,提升了复制的性能。有时候库级并发可能不够,须要作表级并发,或更细粒度的事务级并发。
图 5
并行复制如何处理冲突?并发的世界是美好的,但不能乱并发,不然数据就乱了。Master上面经过锁机制来保证并发的事务有序进行,那么并行复制呢?Slave必需保证回放的顺序与Master上事务执行顺序一致,所以只要作到顺序读取binlog,将不冲突的事务并发执行便可。对于库级并发而言,协调线程要保证执行同一个库的事务放在一个工做线程串行执行;对于表级并发而言,协调线程要保证同一个表的事务串行执行;对于事务级而言,则是保证操做同一行的事务串行执行。
是否粒度越细,性能越好?这个并非必定的。相对于串行复制而言,并行复制多了一个协调线程。协调线程一个重要做用是解决冲突,粒度越细的并发,可能会有更多的冲突,最终可能也是串行执行的,但消耗了大量的冲突检测代价。
第三方复制工具
为何会出现第三方复制工具?第三方复制工具的出现必定是内嵌的复制功能不能知足用户需求,就像半同步复制和并行复制从无到有同样。既然如今mysql复制已经作地这么好了,为何还有第三方复制工具,我能想到最重要的一点是异构复制。在异构数据源迁移场景下,内嵌复制是无能为力的,第三方复制工具经过解析源端的数据库日志,而后在目的端回放,就能达到同步的目的,好比大名鼎鼎的GoldenGate就是一个例子。第三方复制工具一样能很好地实现并发,在并行复制出现以前,这也是一个巨大的优点。另外一方面,就是能够统一下游,避免全部下游都跑到DB上拉binlog,增大DB负载。