《MySQL实战45讲》——学习笔记25 “主备延迟“

正常情况下,主库执行更新生成binlog,binlog传到备库并被正确地执行,备库就能达到跟主库一致的状态,保证数据的最终一致性;但是,MySQL要提供高可用能力,只有最终一致性是不够的,还需要考虑主备延迟

本篇介绍MySQL主备延迟相关的知识,包括什么是主备延迟、产生主备延迟的原因、准备切换的方式;

什么是主备延迟

在介绍主动切换流程的详细步骤之前,先介绍"同步延迟"的概念;

与数据同步有关的时间点主要包括以下3个:

  • 主库A执行完成一个事务,写入binlog,把这个时刻记为T1;
  • 之后传给备库B,把备库B接收完这个binlog的时刻记为T2;
  • 备库B执行完成这个事务,把这个时刻记为T3;

所谓主备延迟,就是同一个事务在备库执行完成的时间和主库执行完成的时间之间的差值,也就是T3-T1

在备库上执行show slave status命令,它的返回结果里面会显示seconds_behind_master(简称sbm),用于表示当前备库延迟了多少秒;

seconds_behind_master的计算方法

每个事务的binlog里面都有一个时间字段,用于记录主库上写入的时间;备库取出当前正在执行的事务的时间字段的值,计算它与当前系统时间的差值,得到seconds_behind_master;

如果主备库机器的系统时间设置不一致,会不会导致主备延迟的值不准?其实不会。

因为,备库连接到主库的时候,会通过执行SELECT UNIX_TIMESTAMP()函数来获得当前主库的系统时间;如果这时候发现主库的系统时间与自己不一致,备库在执行seconds_behind_master计算的时候会自动扣掉这个差值;

需要说明的是,在网络正常的时候,日志从主库传给备库所需的时间是很短的,即T2-T1的值是非常小的;也就是说,网络正常情况下,主备延迟的主要来源是备库接收完binlog和执行完这个事务之间的时间差

当前的主从延迟随时间在T3时刻计算出来,sbm=T3-T1;T1时刻之后:

  • 当主库生成binlog的速度 等于 备库消费中转日志的速度,则可观察到T3时刻之后,sbm稳定在T3-T1;
  • 当主库生成binlog的速度 小于 备库消费中转日志的速度,则可观察到T3时刻之后,sbm不断降低;
  • 当主库生成binlog的速度 大于 备库消费中转日志的速度,则可观察到T3时刻之后,sbm不断增加;

也就是说,主备延迟变大,最直接的表现是,备库消费中转日志(relaylog)的速度,比主库生产binlog的速度要慢

主备延迟的原因

接下来,分析下主备延迟产生的原因;

  • 备库所在机器的性能要比主库所在的机器性能差

例如,2个主库放在2台物理机上,而2备库集中在一台物理机上,或者备库使用性能低于主库的MYSQL套餐;

但是,更新请求对IOPS的压力,在主库和备库上是无差别的;当短时间内主库生成大量binlog时,这个差距决会凸显出来;例如,线上的大表在做数据迁移时,会短时间执行大量的更新操作,这就会导致短时间生成大量的binlog,导致从库在需要一段时间内消费大量来自主库的binlog,就会导致一定时间的主从延迟持续存在;

不过,这种部署现在比较少了;因为主备可能发生切换,备库随时可能变成主库,所以主备库选用相同规格的机器,并且做对称部署,是现在比较常见的情况

  • 备库承担额外的读压力

此时,做了主备对称部署以后,还可能发现出现主备延迟;

原因可能是:认为主库既然提供了写能力,那么备库可以提供一些读能力,用来当读写分离的从库使用,或者一些离线分析的业务直连了备库;

此时,备库除了要承担来自主库binlog的写压力外,还承担一定的读压力,当读操作消耗大量CPU资源时,会影响同步速度,导致主备延迟;

这种情况,我们一般可以这么处理:

  1. 一主多从;除了备库外,可以多接几个从库,让这些从库来分担读的压力;
  2. 通过binlog输出到外部系统,如建立离线表消费主库的binlog,专门做离线分析;
  • 主库执行大事务

大事务这种情况很好理解;如果一个主库上的语句执行10分钟,那这个事务在备库执行也差不多是10分钟,忽略日志从主库到备库的传输时间,导致从库延迟就是10分钟;

下面的图就是大事务下,主从延迟随时间T的关系:

例如,公司的DBA或者MySQL规范可能有这样的提示:不要一次性地用 delete 语句删除太多数据,这就是一个典型的大事务场景;这样的一条事务,执行时间长,大量的数据被锁住;当这条事的binlog务传到从库时,也会消耗大量的执行时间,导致主从延迟拉得很高;

主备切换的方式——可靠性优先策略

  1. 判断备库B现在的seconds_behind_master (sbm),如果小于某个值(比如5秒)继续下一步,否则持续重试这一步;
  2. 把主库A改成只读状态,即把readonly设置为true;
  3. 判断备库B的seconds_behind_master的值,直到这个值变成0为止;
  4. 把备库B改成可读写状态,也就是把readonly设置为false;
  5. 把业务请求切到备库B;

可以看到,这个切换流程中是有不可用时间的;因为在步骤2之后,主库A和备库B都处于readonly状态,也就是说这时系统处于不可写状态,直到步骤5完成后才能恢复;这也是为什么第一步要尽量先让备库的sbm降下来的原因,为了减小从主库不可写到备库可写的时间间隔;

主备切换的方式——可用性优先策略

不等主备数据同步,直接把连接切到备库B,并且让备库B可以读写,那么系统几乎就没有不可用时间了;把这个切换流程,暂时称作可用性优先流程;

这个切换流程的代价,就是可能出现数据不一致的情况

例如有下面这张表:

mysql> CREATE TABLE `t` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `c` int(11) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

insert into t(c) values(1),(2),(3);

预期插入(4,4),(5,5)这两条数据,因此客户端先后执行以下命令:

# id为自增主键 因此无需显示的指定
insert into t(c) values(4);
insert into t(c) values(5);

此过程中发生了主从切换,且使用"可用性优先策略";

若此时 binlog_format=mixed

若此时 binlog_format=row

 从上面的分析中,可以看到一些结论:

  1. 使用row格式的binlog时,数据不一致的问题更容易被发现,因为抛异常了;而使用mixed或者statement格式的binlog时,数据很可能悄悄地就不一致了;如果你过了很久才发现数据不一致的问题,很可能这时的数据不一致已经不可查,或者连带造成了更多的数据逻辑不一致;主备切换的可用性优先策略会导致数据不一致;
  2. 因此,大多数情况下,建议使用可靠性优先策略;毕竟对数据服务来说的话,数据的可靠性一般还是要优于可用性的;

下篇文章:《MySQL实战45讲》——学习笔记26 “备库怎么追上主库“

本章参考:25 | MySQL是怎么保证高可用的?-极客时间

猜你喜欢

转载自blog.csdn.net/minghao0508/article/details/128851747