自学内容网 自学内容网

MySQL45讲 第二十六讲 备库为什么会延迟好几个小时?——阅读总结

MySQL45讲 第二十六讲 备库为什么会延迟好几个小时?——阅读总结

在MySQL数据库的主备架构中,备库延迟是一个需要重点关注的问题。它可能影响系统的可用性和数据的一致性,尤其是在主库压力较大时,备库延迟可能达到数小时甚至永远无法追上主库。今天,我们将深入探讨MySQL备库延迟的原因,重点聚焦于备库并行复制能力以及各种并行复制策略的原理、优缺点。


一、MySQL主备流程与并行复制的必要性

(一)主备流程回顾

为了更好地理解备库并行复制,我们先回顾一下MySQL的主备流程图(如图1所示)。

在这里插入图片描述

在这个流程中,客户端写入主库,主库生成binlog。备库通过sql_thread读取中转日志(relay log)来执行数据更新,以保持与主库的数据一致。然而,在官方5.6版本之前,MySQL只支持单线程复制,当主库并发高、TPS高时,就会出现严重的主备延迟问题,因为单线程复制能力往往无法跟上主库生成日志的速度。

(二)并行复制的重要性

从单线程复制到多线程复制的演进,是为了解决主备延迟问题。多线程复制机制通过将原来的sql_thread拆分成多个worker线程,提高备库应用日志的速度,从而减少主备延迟。例如,在高并发的业务场景下,多线程复制能够更有效地利用系统资源,使备库能够更快地处理主库传来的日志,提升系统的整体性能。

在这里插入图片描述

work线程的个数,就是由参数 slave_parallel_workers决定的。把这个值设置为8~16之间最好(32核物理机的情况),毕竟备库还有可能要提供读查询,不能把CPU都吃光了。

问题1:事务能不能按照轮询的方式分发给各个worker,也就是第一个 事务分给worker_1,第二个事务发给worker_2呢?

不行的。因为,事务被分发给worker以后,不同的worker就独立执行了。但是,由于CPU 的调度策略,**可能第二个事务最终比第一个事务先执行。**而如果这时候刚好这两个事务更新的是同一行,会导致主备不 一致的问题。

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

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

基于以上两个问题,主备复制在coordinator中需要保证以下两个原则:

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

二、多线程复制策略详解

(一)MySQL 5.5版本并行复制策略(非官方)

  1. 按表分发策略

    • 基本思路:**如果两个事务更新不同的表,它们就可以并行。**每个worker线程对应一个hash表,用于保存当前正在这个worker的“执行队列”里的事务所涉及的表。hash表的key是“库名.表名”,value是一个数字,表示队列中有多少个事务修改这个表。
    • 事务分配流程
      • 当有事务分配给worker时,事务里面涉及的表会被加到对应的hash表中。
      • 假设新事务T修改的行涉及到表t1和t3,先判断事务T和每个worker队列的冲突关系。若事务T跟多于一个worker冲突,coordinator线程就进入等待;若只跟一个worker冲突,就分配给该worker;若跟所有worker都不冲突,就分配给最空闲的worker。
    • 优缺点:在多个表负载均匀的场景里应用效果好,但如果碰到热点表(所有更新事务都涉及某一个表),所有事务都会被分配到同一个worker中,就变成单线程复制了。

    针对热点表,有没有什么办法可以解决一下?这时候需要按行分发策略。

  2. 按行分发策略

    • 核心思路:如果两个事务没有更新相同的行,它们在备库上可以并行执行。此模式要求binlog格式必须是row。判断事务冲突的规则是“修改同一行”,数据结构与按表分发类似,但key为“库名 + 表名 + 唯一键的值”(考虑主键和唯一索引)。
    • 优缺点:并行度更高,但对于操作很多行的大事务,存在耗费内存(如删除100万行数据,hash表要记录100万个项)和耗费CPU(解析binlog和计算hash值成本高)的问题。因此,通常会设置一个阈值,单个事务超过行数阈值(如10万行),就暂时退化为单线程模式。

(二)MySQL 5.6版本并行复制策略

事实上,按表和按行两个策略又没有被合到官方。官方5.6版本支持按库并行复制,用于决定分发策略的hash表里,key就是数据库名。

  1. 并行效果取决于压力模型:如果主库上有多个DB且压力均衡,使用该策略效果较好;但如果主库上的表都在同一个DB里,或者不同DB热点不同,该策略就无法发挥并行效果。
  2. 优势
    • 构造hash值快,只需要库名;
    • 不要求binlog格式,statement格式的binlog也能容易拿到库名。

(三)MariaDB并行复制策略

  1. 利用redo log组提交特性:能够在同一组里提交的事务,一定不会修改同一行;主库上可以并行执行的事务,备库上也一定可以并行执行。

  2. 实现方式:在一组里面一起提交的事务,有一个相同的commit_id,下一组就是commit_id + 1,commit_id直接写到binlog里面。传到备库应用时,相同commit_id的事务分发到多个worker执行,一组全部执行完成后,coordinator再取下一批。

  3. 存在问题没有实现“真正的模拟主库并发度”,在备库上要等第一组事务完全执行完成后,第二组事务才能开始执行,系统吞吐量不够;容易被大事务拖后腿,大事务执行时,只有一个worker线程在工作,浪费资源。

    在这里插入图片描述

(四)MySQL 5.7并行复制策略

  1. 参数控制并行策略:由参数slave_parallel_type控制,可配置为DATABASE(类似MySQL 5.6的按库并行策略)或LOGICAL_CLOCK(类似MariaDB策略,但针对并行度做了优化)。
  2. 优化思路:同时处于prepare状态的事务,在备库执行时可以并行;处于prepare状态的事务,与处于commit状态的事务之间,在备库执行时也可以并行。MySQL 5.7中binlog的组提交相关参数(binlog_group_commit_sync_delaybinlog_group_commit_sync_no_delay_count)可用于制造更多“同时处于prepare阶段的事务”,增加备库复制的并行度。

(五)MySQL 5.7.22并行复制策略

  1. 基于WRITESET的并行复制:新增参数binlog - transaction - dependency - tracking控制是否启用。可选值包括COMMIT_ORDER(根据同时进入prepare和commit判断是否并行)、WRITESET(对于事务涉及更新的每一行,计算hash值组成集合writeset,无交集的事务可并行)和WRITESET_SESSION(在WRITESET基础上,保证主库上同一个线程先后执行的两个事务在备库执行时的先后顺序)。
  2. 优势:writeset在主库生成后直接写入binlog,备库执行时无需解析binlog内容,节省计算量;不需要扫整个事务的binlog来决定分发worker,更省内存;不依赖binlog内容,binlog是statement格式也可并行。但对于“表上没主键”和“外键约束”的场景,无法并行,会退化为单线程模型。

三、主备延迟问题的进一步探讨

(一)大事务对备库延迟的影响

大事务不仅影响主库性能,也是造成备库复制延迟的主要原因之一。例如,一次性删除大量数据或执行大表DDL操作,在主库执行时间长,导致备库延迟。在平时开发中,应尽量减少大事务操作,将大事务拆分成小事务,以降低对主备延迟的影响。

(二)备库延迟的其他场景

  1. 热点表问题:如按表分发策略中,所有更新事务集中在一个热点表时,会导致并行复制失效,备库延迟增加。
  2. 长事务阻塞:备库起长事务(如begin; select * from t limit 1;后长时间不提交),若主库对相关表进行DDL操作,在备库应用时会被堵住,导致主备延迟。

四、总结与思考

(一)总结

MySQL的多线程复制策略经历了多个版本的演进,从非官方的按表、按行分发策略到官方的按库并行、基于组提交和WRITESET的并行复制策略。不同策略各有优缺点,适用场景不同。DBA需要根据业务场景选择合适的策略,业务开发人员也可从中获取灵感优化开发工作。同时,大事务和一些特殊场景(如热点表、长事务)会对备库延迟产生影响,在实际应用中需特别注意。


原文地址:https://blog.csdn.net/KELLENSHAW/article/details/143916924

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!