一篇文带你彻底解决mysql的主从复制延迟问题,2024年最新东软java面试题

文章讨论了MySQL主从复制中可能出现的延迟原因,包括写库压力、事务执行、单线程操作、IO竞争、网络带宽和DDL数量等,并提供了通过架构优化、从库配置调整(如sync_binlog设置)、并行复制策略和硬件升级等方式来解决这些问题的方法。
摘要由CSDN通过智能技术生成

2、备库充当了读库,一般情况下主要写的压力在于主库,那么备库会提供一部分读的压力,而如果备库的查询压力过大的话,备库的查询消耗了大量的CPU资源,那么必不可少的就会影响同步的速度

3、大事务执行,如果主库的一个事务执行了10分钟,而binlog的写入必须要等待事务完成之后,才会传入备库,那么此时在开始执行的时候就已经延迟了10分钟了

4、主库的写操作是顺序写binlog,从库单线程去主库顺序读binlog,从库取到binlog之后在本地执行。mysql的主从复制都是单线程的操作,但是由于主库是顺序写,所以效率很高,而从库也是顺序读取主库的日志,此时的效率也是比较高的,但是当数据拉取回来之后变成了随机的操作,而不是顺序的,所以此时成本会提高。

5、 从库在同步数据的同时,可能跟其他查询的线程发生锁抢占的情况,此时也会发生延时。

6、 当主库的TPS并发非常高的时候,产生的DDL数量超过了一个线程所能承受的范围的时候,那么也可能带来延迟

7、 在进行binlog日志传输的时候,如果网络带宽也不是很好,那么网络延迟也可能造成数据同步延迟

这些就是可能会造成备库延迟的原因

3、如何解决复制延迟的问题


先说一些虚的东西,什么叫虚的东西呢?就是一听上去感觉很有道理,但是在实施或者实际的业务场景中可能难度很大或者很难实现,下面我们从几个方面来进行描述:

1、架构方面


1、业务的持久化层的实现采用分库架构,让不同的业务请求分散到不同的数据库服务上,分散单台机器的压力

2、服务的基础架构在业务和mysql之间加入缓存层,减少mysql的读的压力,但是需要注意的是,如果数据经常要发生修改,那么这种设计是不合理的,因为需要频繁地去更新缓存中的数据,保持数据的一致性,导致缓存的命中率很低,所以此时就要慎用缓存了

3、使用更好的硬件设备,比如cpu,ssd等,但是这种方案一般对于公司而言不太能接受,原因也很简单,会增加公司的成本,而一般公司其实都很抠门,所以意义也不大,但是你要知道这也是解决问题的一个方法,只不过你需要评估的是投入产出比而已

2、从库配置方面


1、修改sync_binlog的参数的值

想要合理设置此参数的值必须要清楚地知道binlog的写盘的流程:

image

可以看到,每个线程有自己的binlog cache,但是共用同一份binlog。

图中的write,指的就是把日志写入到文件系统的page cache,并没有把数据持久化到磁盘,所以速度快

图中的fsync,才是将数据持久化到磁盘的操作。一般情况下,我们认为fsync才占用磁盘的IOPS

而write和fsync的时机就是由参数sync_binlog来进行控制的。

1、当sync_binlog=0的时候,表示每次提交事务都只write,不fsync

2、当sync_binlog=1的时候,表示每次提交事务都执行fsync

3、当sync_binlog=N的时候,表示每次提交事务都write,但积累N个事务后才fsync。

一般在公司的大部分应用场景中,我们建议将此参数的值设置为1,因为这样的话能够保证数据的安全性,但是如果出现主从复制的延迟问题,可以考虑将此值设置为100~1000中的某个数值,非常不建议设置为0,因为设置为0的时候没有办法控制丢失日志的数据量,但是如果是对安全性要求比较高的业务系统,这个参数产生的意义就不是那么大了。

2、直接禁用salve上的binlog,当从库的数据在做同步的时候,有可能从库的binlog也会进行记录,此时的话肯定也会消耗io的资源,因此可以考虑将其关闭,但是需要注意,如果你搭建的集群是级联的模式的话,那么此时的binlog也会发送到另外一台从库里方便进行数据同步,此时的话,这个配置项也不会起到太大的作用

3、设置innodb_flush_log_at_trx_commit 属性,这个属性在我讲日志的时候讲过,用来表示每一次的事务提交是否需要把日志都写入磁盘,这是很浪费时间的,一共有三个属性值,分别是0(每次写到服务缓存,一秒钟刷写一次),1(每次事务提交都刷写一次磁盘),2(每次写到os缓存,一秒钟刷写一次),一般情况下我们推荐设置成2,这样就算mysql的服务宕机了,卸载os缓存中的数据也会进行持久化。

4、从根本上解决主从复制的延迟问题


很多同学在自己线上的业务系统中都使用了mysql的主从复制,但是大家需要注意的是,并不是所有的场景都适合主从复制,一般情况下是读要远远多于写的应用,同时读的时效性要求不那么高的场景。如果真实场景中真的要求立马读取到更新之后的数据,那么就只能强制读取主库的数据,所以在进行实现的时候要考虑实际的应用场景,不要为了技术而技术,这是很严重的事情。

在mysql5.6版本之后引入了一个概念,就是我们通常说的并行复制,如下图:

image

通过上图我们可以发现其实所谓的并行复制,就是在中间添加了一个分发的环节,也就是说原来的sql_thread变成了现在的coordinator组件,当日志来了之后,coordinator负责读取日志信息以及分发事务,真正的日志执行的过程是放在了worker线程上,由多个线程并行的去执行。

– 查看并行的slave的线程的个数,默认是0.表示单线程

show global variables like ‘slave_parallel_workers’;

– 根据实际情况保证开启多少线程

set global slave_parallel_workers = 4;

– 设置并发复制的方式,默认是一个线程处理一个库,值为database

show global variables like ‘%slave_parallel_type%’;

– 停止slave

stop slave;

– 设置属性值

set global slave_parallel_type=‘logical_check’;

– 开启slave

start slave

– 查看线程数

show full processlist;

通过上述的配置可以完成我们说的并行复制,但是此时你需要思考几个问题

1、在并行操作的时候,可能会有并发的事务问题,我们的备库在执行的时候可以按照轮训的方式发送给各个worker吗?

答案是不行的,因为事务被分发给worker以后,不同的worker就开始独立执行了,但是,由于CPU的不同调度策略,很可能第二个事务最终比第一个事务先执行,而如果刚刚好他们修改的是同一行数据,那么因为执行顺序的问题,可能导致主备的数据不一致

2、同一个事务的多个更新语句,能不能分给不同的worker来执行呢?

答案是也不行,举个例子,一个事务更新了表t1和表t2中的各一行,如果这两条更新语句被分到不同worker的话,虽然最终的结果是主备一致的,但如果表t1执行完成的瞬间,备库上有一个查询,就会看到这个事务更新了一半的结果,破坏了事务逻辑的隔离性。

我们通过讲解上述两个问题的最主要目的是为了说明一件事,就是coordinator在进行分发的时候,需要遵循的策略是什么?

1、不能造成更新覆盖。这就要求更新同一行的两个事务,必须被分发到同一个worker中。

2、同一个事务不能被拆开,必须放到同一个worker中。

听完上面的描述,我们来说一下具体实现的原理和过程

如果让我们自己来设计的话,我们应该如何操作呢?这是一个值得思考的问题。其实如果按照实际的操作的话,我们可以按照粒度进行分类,分为按库分发,按表分发,按行分发。

其实不管按照什么方式进行分发,大家需要注意的就是在分发的时候必须要满足我们上面说的两条规则,所以当我们进行分发的时候要在每一个worker上定义一个hash表,用来保存当前这个work正在执行的事务所涉及到的表。hash表的key值按照不同的粒度需要存储不同的值:

按库分发:key值是数据库的名字,这个比较简单

按表分发:key值是库名+表名

按行分发:key值是库名+表名+唯一键

1、MySQL5.6版本的并行复制策略


其实从mysql的5.6版本开始就已经支持了并行复制,只是支持的粒度是按库并行,这也是为什么现在的版本中可以选择类型为database,其实说的就是支持按照库进行并行复制。

但是其实用过的同学应该都知道,这个策略的并行效果,取决于压力模型。如果在主库上有多个DB,并且各个DB的压力均衡,使用这个策略的效果会很好,但是如果主库的所有表都放在同一DB上,那么所有的操作都会分发给一个worker,变成单线程操作了,那么这个策略的效果就不好了,因此在实际的生产环境中,用的并不是特别多

2、mariaDB的并行复制策略


在mysql5.7的时候采用的是基于组提交的并行复制,换句话说,slave服务器的回放与主机是一致的,即主库是如何并行执行的那么slave就如何怎样进行并行回放,这点其实是参考了mariaDB的并行复制,下面我们来看下其实现原理。

mariaDB的并行复制策略利用的就是这个特性:

1、能够在同一组里提交的事务,一定不会修改同一行;

2、主库上可以并行执行的事务,备库上也一定是可以并行执行的。

在实现上,mariaDB是这么做的:

1、在一组里面一起提交的事务,有一个相同的commit_id,下一组就是commit_id+1;

2、commit_id直接写到binlog里面;

3、传到备库应用的时候,相同commit_id的事务会分发到多个worker执行;

4、这一组全部执行完成后,coordinator再去取下一批。

这是mariaDB的并行复制策略,大体上看起来是没有问题的,但是你仔细观察的话会发现他并没有实现“真正的模拟主库并发度”这个目标,在主库上,一组事务在commit的时候,下一组事务是同时处于“执行中”状态的。

我们真正想要达到的并行复制应该是如下的状态,也就是说当第一组事务提交的是,下一组事务是运行的状态,当第一组事务提交完成之后,下一组事务会立刻变成commit状态

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

更多:Java进阶核心知识集

包含:JVM,JAVA集合,网络,JAVA多线程并发,JAVA基础,Spring原理,微服务,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存等等

image

高效学习视频

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

线程并发,JAVA基础,Spring原理,微服务,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存等等

[外链图片转存中…(img-AAkXjDf7-1712694468375)]

高效学习视频

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-9leup6Zt-1712694468375)]

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL主从复制是一种常用的数据库架构设计,用于提高数据库的可用性和性能。它通过将数据从一个MySQL主服务器复制到一个或多个从服务器来实现。 主从复制的工作原理如下: 1. 主服务器(Master)接收到写操作(INSERT、UPDATE、DELETE)后,将操作记录写入二进制日志(Binary Log)。 2. 从服务器(Slave)连接到主服务器,并请求复制主服务器的二进制日志。 3. 主服务器将二进制日志传输给从服务器,从服务器将其写入中继日志(Relay Log)。 4. 从服务器读取中继日志,并将其中的操作应用到自己的数据库中,实现数据的同步。 读写分离是在主从复制的基础上进一步优化数据库性能的一种方式。它将读操作和写操作分离,使得读操作可以在从服务器上进行,而写操作仍然在主服务器上进行。这样可以提高数据库的并发处理能力和读取性能。 面试题相关问题: 1. 什么是MySQL主从复制? 2. 主从复制的工作原理是什么? 3. 为什么要使用MySQL主从复制? 4. 读写分离是什么?有什么优势? 5. 主从复制和读写分离的应用场景有哪些? 6. 主从复制可能存在的问题和风险有哪些? 7. 如何配置MySQL主从复制和读写分离? 8. 如何监控和管理MySQL主从复制和读写分离的状态? 9. 有没有其他替代MySQL主从复制和读写分离的方案? 10. 如何保证主从复制的数据一致性和可靠性?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值