MySQL - 主从复制的几种方式
1. 什么是主从复制
主从复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数据库。
可以理解为,主数据库的数据的任何变化,从数据库都会跟着发生变化。
2. 主从复制的作用
在从服务器可以执行查询工作,降低主服务器压力;(主库写,从库读,降压)读写分离
在从主服务器进行备份,避免备份期间影响主服务器服务;容灾
当主服务器出现问题时,可以切换到从服务器。提高可用性
3. 主从复制的基本原理
步骤含义:
SQL语句操作变化存入BinLog日志中
slave上线,连接到master服务器,进行数据同步
dump thread线程把Binlog数据发送到slave中
slave启动之后,创建一个I/O线程,读取master传过来的Binlog内容并写入到Relay log.
slave还会创建一个SQL线程,从Relay log里面读取内容,从Exec_Master_Log_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db.
3.1. 并行加速复制
传统的MySQL(5.6 版本之前)主从复制是单线程复制,即:1个dump thread线程,1个IO线程,1个SQL线程
想要提高复制的效率,很自然考虑多线程,虽然有3种线程可以扩展为多线程。但是MySQL只将SQL线程扩展为多线程
为什么Dump和IO线程不能多线程?
dump线程和IO线程都是负责网络传输,如果将这里扩展为多线程那么会将一份Binlog日志分割为多份,并行传输,那么在slave端将会要额外的增加代码考虑如何将多份日志还原为原来的Binlog,大大增加难度。
性能瓶颈不在IO,扩展后也没有多大效率提升。
画外音:为什么Redis 6.0使用IO多线程增强性能,MySQL这里使用IO多线程却不行?
Redis是多个Client节点一个Server节点(暂且这么看),IO线程需要处理多个不同Client来源的请求;MySQL主从复制,本质上是1个Client端一个Server端,增大IO线程也无济于事。
SQL线程并行后的难点
相同两个事务的执行顺序。假设A,B两个事务,A先执行,B后执行,都同时改同一行数据,如果主从同步过程中,因为并行执行,B先执行,A后执行,那么将导致数据不一致问题。所以需要一个机制去防止此类事情的发生。
对于这个问题,MySQL会判断当前需要复制的事务Id和与之前复制完毕的事务id进行比对,判断是否处于当前执行完毕事务之后,否则只能等待前驱事务复制完毕。(大概原理,本文不是讲解并行复制,不深入讲解)
4. MySQL主从复制的方式
4.1. 异步复制
MySQL 默认的复制策略,Master处理事务过程中,将其写入Binlog就会通知Dump thread线程处理,然后完成事务的提交,不会关心是否成功发送到任意一个slave中
问题:一旦Master 崩溃,发送主从切换将会发送数据不一致性的风险。
画外音:性能最好
4.2. 半同步复制
Master处理事务过程中,提交完事务后,必须等至少一个Slave将收到的binlog写入relay log返回ack才能继续执行处理用户的事务。
配置
rpl_semi_sync_master_wait_point = AFTER_COMMIT (什么时间点开始等ack)【这里MySQL 5.5并没有这个配置,MySQL5.7 为了解决半同步的问题而设置的,下文有讲解】
rpl_semi_sync_master_wait_for_slave_count = 1 (最低必须收到多少个slave的ack)
rpl_semi_sync_master_timeout = 100(等待ack的超时时间)
问题:
一旦Ack超时,将退化为异步复制模式,那么异步复制的问题也将发送
性能下降,增多至少一个RTT时间
数据不一致性问题,因为等待ACK的点是Commit之后,此时Master已经完成数据变更,用户已经可以看到最新数据,当Binlog还未同步到Slave时,发生主从切换,那么此时从库是没有这个最新数据的,用户又看到老数据。
4.3. 增强半同步复制
增强半同步和半同步不同是,等待ACK时间不同
rpl_semi_sync_master_wait_point = AFTER_SYNC(唯一区别)
半同步的问题是因为等待ACK的点是Commit之后,此时Master已经完成数据变更,用户已经可以看到最新数据,当Binlog还未同步到Slave时,发生主从切换,那么此时从库是没有这个最新数据的,用户又看到老数据。
增强半同步将等待ACK的点放在提交Commit之前,此时数据还未被提交,外界看不到数据变更,此时如果发送主从切换,新库依然还是老数据,不存在数据不一致的问题。
问题:
一旦Ack超时,将退化为异步复制模式,那么异步复制的问题也将发送
性能下降,增多至少一个RTT时间
如果超时时间设置很大,然后因为网络原来长时间收不到ACK,用户提交是被挂起的,可用性收到打击(半同步一样存在)
画外音:感觉MySQL因为直接提供增强半同步,半同步类似个过度产品
4.4. 组复制
MySQL Group Replication(MGR)
MySQL在引擎层完成Prepare操作写Redo日志之后,会被MySQL的预设Hook拦截进入MGR层
MGR层将事务信息打包通过Paxos协议发送到全部节点上,只要集群中过半节点回复ACK,那么将告诉所有节点数据包同步成功,然后每个节点开始自己认证(certify)通过就开始写Binlog,提交事务或者写relay log,数据同步,如果认证不通过则rollback
什么是Certify?
在不同服务器上并发执行的事务之间可能存在冲突。这种冲突是通过检查和比较两个不同的并发事务的写入集来检测的,这个过程称为认证
在认证期间,冲突检测是在行级别执行的:如果在不同服务器上执行的两个并发事务更新了同一行,则存在冲突。
冲突解决过程指出,首先排序的事务将在所有服务器上提交,而第二次排序的事务将中止,因此将在原始服务器上回滚并被组中的其他服务器丢弃。
总结:MGR内部实现了分布式数据一致性协议,paxos通过其来保证数据一致性。
问题
性能不高
TP999升高,吞吐量降低;增大20%~30%响应时间
5. 对比
我们考虑架构的时候,不应该过于关心它能干啥,应该考虑每一种方式它不能干啥
版权声明: 本文为 InfoQ 作者【Aaron_涛】的原创文章。
原文链接:【http://xie.infoq.cn/article/25d72d513e3c7094eaa82cabc】。文章转载请联系作者。
评论