大家好,我是楼仔!MySQL主从一直是面试的常客。虽然里面的知识点很基础,但是能够全部答对的同学并不多。比如之前面试小米的时候,被问到主从复制的原理和主从延迟的解决方法。之前面试遇到过哪些MySQL主从问题?一、MySQL主从1.1什么是MySQL?主从?所谓MySQL主从,就是建立两个相同的数据库,一个是主库,一个是从库。主库对外提供读写操作,从库对外提供读操作。1.2为什么要使用MySQL主从?对于数据库单机部署,在4核8G机器上运行MySQL5.7时,大概可以支持500TPS和10000QPS。从分离。大多数系统的访问模型都是读多写少,读写请求量的差异可能达到几个数量级,所以我们可以采用一主多从的方式。主库只负责编写和查询一些核心逻辑。从库只负责查询,提高查询性能,减轻主库压力。当主库宕机时,可以将从库切入主库,保证服务的高可用,然后主库也可以做数据容灾备份。整体场景总结如下:读写分离:从库提供查询,减轻主库压力,提高性能;高可用:从库发生故障时可以切换,保证服务高可用;数据备份:数据备份到从库,防止服务器宕机导致数据丢失。2.主从复制2.1主从复制原理MySQL的主从复制依赖于binlog,它记录了MySQL上的所有变化,并以二进制的形式保存在磁盘上,作为一个二进制日志文件。主从复制就是将binlog中的数据从主库传输到从库。一般这个过程是异步的,即对master库的操作不会等待binlog同步完成。详细过程如下:主库写入binlog:将主库的更新SQL(update、insert、delete)写入binlog;主库发送binlog:主库创建日志转储线程向从库发送binlog;从库写入relaylog:当从库连接到master节点时,会创建IO线程请求master库更新的binlog,并将接收到的binlog信息写入一个名为relaylog的日志文件;从库回放:从库也会创建一个SQL线程读取relaylog中的内容,在从库回放,最终实现主从一致性。2.2如何保证主从一致性主从库数据同步时,突然中断怎么办?因为主库和从库之间维护了一个长链接,所以主库内部有一个线程,专门为从库的这个长链接服务的。对于下面这种情况,如果主库执行如下SQL,其中a和create_time都是索引:deletefromtwherea>'666'andcreate_time<'2022-03-01'limit1;我们知道数据选择a索引一般和选择create_time索引不同,最后limit1出数据。所以就会出现这样的情况:当binlog=statement格式时,主库在执行这条SQL时使用索引a,而从库在执行这条SQL时使用索引create_time,最后主从数据不一致了.那我们怎么解决呢?我们可以把binlog的格式改成行。行格式的binlog日志记录的不是原始的SQL文本,而是两个事件:Table_map和Delete_rows。table_map事件描述了要操作的表,Delete_rows事件用于定义要删除的行为,记录具体要删除的行数。行格式的binlog记录了要删除的主键ID信息,所以不会出现主从不一致的情况。但是如果SQL删除10万行数据,使用行格式会占用大量空间。10万行数据都在binlog里面,写binlog的时候也消耗IO。但是statement格式的binlog可能会造成数据不一致。设计MySQL的大叔想了一个折中方案。混合格式的binlog其实就是行格式和语句格式的混合。当MySQL判断数据可能不一致时,使用行格式,否则使用语句格式。3.主从延迟有时候遇到无法从数据库获取信息的奇葩问题时,我们会纠结代码中是否有某种逻辑会删除之前写入的内容,但是一段时间后你会发现oftime再次去查询的时候,可以重新读取数据。这基本上就是主从延迟。主从延迟其实就是“从库重放”完成时间和“主库写binlog”完成时间的差值,会导致从库查询到的数据和主库不一致。3.1主从延时原理说到MySQL数据库的主从同步延时原理,就不得不从MySQL的主从复制原理说起:MySQL的主从复制是单线程操作,主从库为所有DDL和DML生成二进制日志。binlog是Sequentialwriting,所以效率很高;Slave的Slave_IO_Running线程会去主库取日志,放入relaylog,效率会更高;Slave的Slave_SQL_Running线程会在Slave中实现主库的DDL和DML操作,而DML和DDLIO操作是随机的,不是顺序的,所以成本会很高,另外对Slave的查询可能会造成锁争论。由于Slave_SQL_Running也是单线程的,一个DDL卡主需要执行10分钟,然后所有SubsequentDDL都会等这个DDL执行完再继续,导致了延迟。总结主从延迟的主要原因:主从延迟主要发生在“relaylogplayback”这一步。当主库的TPS并发很高,产生的DDL量超过了从库一个SQL线程所能承受的范围,那么延迟就会发生,当然也有可能会出现锁等待的情况从库大查询语句。3.2主从延迟情况从库机性能:从库机性能比主库机差,选择与主从库相同规格的机器即可。从库压力很大:可以搭建主多从架构,也可以把binlog接入Hadoop等系统,让他们提供查询能力。从库过多:为避免副本节点过多,一般以3-5个从库为宜。大事务:如果执行一个事务需要10分钟,那么主库执行完之后,再由从库执行。最后,这个事务可能会导致从库延迟10分钟。日常开发中,一次删除的SQL不要太多,需要分批进行,大表的DDL语句也会导致大事务。网络延迟:优化网络,比如将带宽从20M升级到100M。低版本MySQL:低版本的MySQL只支持单线程复制。如果主库并发高,来不及转移到从库,就会造成延迟。您可以切换到支持多线程复制的更高版本的MySQL。3.3主从延迟解决方案我们一般会使用从库的滞后时间作为数据库的关键指标进行监控和告警。正常时间在毫秒级别。一旦滞后时间达到秒级,就需要报警。除了缩短主从延迟时间,还有其他方法可以解决这个问题。基本原则是尽量不要去查询从库。具体解决方案如下:使用缓存:当我们同步写入数据库时??,我们也保存了数据写入缓存和查询数据时,会先查询缓存,但是这种情况会造成MySQL和MySQL之间的数据一致性问题雷迪斯。查询主库:直接查询主库,这种情况会给主库造成太大的压力,不推荐这种方式。数据冗余:对于一些异步处理场景,如果只丢掉数据ID,消费数据时,需要查询从库。我们可以把所有的数据都扔到消息队列中,这样消费者就不需要查询从库了。(这种情况应该不太可能发生,数据轮换了,mysql主从没有同步,去找DBA就可以了)在实际应用场景中,对于一些非常核心的场景,比如库存,支付订单等,如果需要直接查询从库,其他非核心场景不要查询主库。4、主从切换4.1一主一从,两台机器A和B,A为主库,负责读写,B为从库,负责读取数据。如果A库出现故障,B库成为负责读写的主库。故障修复后,A成为从库,主库B同步数据到从库A。优点:从库支持读,分担主库压力,提高并发性,当一台机器出现故障时可以自动切换,操作比较简单,公司的从库也可以起到数据备份的作用;缺点:一个从库,并发支持还是不够,而且一共两台机器,还是有概率同时失败,可用性不够高。对于一主一从的模式,一般小公司都会这样使用,但是这种模式下,主从分离其实意义不大,因为小公司的流量不高,而且它更多的是为了数据库的可用性和数据备份。4.2一主多从一个主库和多个从库,A为主库,负责读写,B、C、D为从库,负责读取数据。如果A库出现故障,B库成为负责读写的主库,C、D负责读。故障修复后,A也成为从库,主库B同步数据到从库A。优点:多个从库支持读,分担主库压力,显着提高读并发度。缺点:只有一台主机写入,写入并发度不高。百度、滴滴等大公司基本上都是采用这种一主多从的模式。因为查询流量太大,必须要读写分离,还需要支持服务高可用和数据容灾。
