如何保证主从一致及主从延迟的问题

简介:主库与从库之前同步数据是通过一个长连接来实现的,主库内部有一个线程,专门维护从库的这个长连接。如果主库和从库数据同步时,这个长连接突然中断了怎么办?还有删除数据时使用了limit和order by排序,但是索引问题导致主从删除的数据不一致怎么办?

今天的主题是MySQL主从一致及主从同步延时的问题,解决这个问题之前我们需要了解什么是主从及主从复制的原理。大家可以看看我之前的【MySQL主从复制-基于binlog日志】的文章。

1.如何保证主从一致

主库与从库之前同步数据是通过一个长连接来实现的,主库内部有一个线程,专门维护从库的这个长连接。如果主库和从库数据同步时,这个长连接突然中断了怎么办?还有删除数据时使用了limit和order by排序,但是索引问题导致主从删除的数据不一致怎么办?

我们先来看看下面的删除SQL:

delete from orders where status < 0 and create_time<'2023-04-21' limit 1;

SQL执行时选择了 status 索引和选择 create_time 索引,最后 limit 1 出来的数据是不一样的。如果我们是基于binlog日志实现的主从同步并且 binlog=statement 格式时,主库执行这条SQL时,使用的是索引 status ,同步到从库执行这条SQL时,使用了索引 create_time ,最后导致主从数据不一致。

对于这一类的主从不一致的问题我们可以将 binlog 改为 row 格式。因为row格式记录的不是SQL原文,而是两个事件table_mapdelete_rows 。row格式的binlog记录的就是要删除的主键ID信息,因此不会出现主从不一致的问题。

  • table_map:操作的表
  • delete_rows:用于定义要删除的行为,记录删除的具体行数

不过这种方法有一个很大的缺点,占用空间大。

假设SQL删除10万行数据,10万条数据都在 binlog 里面,写binlog的时候也很耗IO。于是MySQL就出现了一个折中方案,mixed格式的binlog。其实就是row和statement格式的混合,当MySQL判断可能数据不一致时,就使用row格式,否则使用statement格式

2.主从延迟

有时候我们写入主库后再去从库读取数据时,发现读取不到数据,但是过了一会儿又可以读取到数据,这基本就是主从延迟导致的。

上面我们说过了主库通过一个长连接来实现同步数据到从库,但是这个同步的过程需要经过网络传输,从库解析并执行SQL,这个过程是需要一定的时间。在这个同步的时间内会导致从库查询的数据和主库不一致。

注意:主库的TPS并发较高时,产生的DDL数量超过从库同步的SQL线程所能承受的范围,延迟会更严重。

如果从库的一些query语句产生了锁等待时,也会导致延迟。毕竟加锁后同步的线程无法执行同步SQL。

如果大家不了解主从复制原理的可以看看我之前的MySQL主从复制-基于binlog日志的文章。

2.1 主从延迟解决方案

解决这类问题,除了缩短主从延迟的时间,还有一些其他的办法,基本原理都是尽量不查询从库,具体方案如下:

  • 使用缓存:我们在同步写数据库的同时,也把数据写到缓存,查询数据时,会先查询缓存,不过这种情况会带来 MySQL 和 Redis 数据一致性问题
  • 查询主库:直接查询主库,这种情况会给主库太大压力
  • 数据冗余:对于一些异步处理的场景,如果只扔数据 ID,消费数据时,需要查询从库,我们可以把数据全部都扔给消息队列,这样消费者就无需再查询从库。

在实际应用场景中,对于一些非常核心的场景,比如库存,支付订单等直接查询主库,其它非核心场景可以查询从库。

有遗漏或者不对的可以在我的公众号留言哦

编程经验共享公众号二维码

编程经验共享公众号二维码
更多内容关注公众号
Copyright © 2021 编程经验共享 赣ICP备2021010401号-1