MySQL主从复制(三):主从延迟

主备流程图:

谈到主备的复制能力,要关注的是上图中的两个黑色箭头。

一个箭头代表了客户端写入主库,另一个箭头代表的是sql_thread执行中转日志(relay log)。如果用箭头的粗细来代表并行度的话,那么真实情况就如图所示,第一个箭头要明显粗于第二个箭头。

1)在主库上,影响并发度的原因就是各种锁了。由于InnoDB引擎支持行锁, 除了所有并发事务都在更新同一行(热点行) 这种极端场景外, 它对业务并发度的支持还是很友好的。 所以, 你在性能测试的时候会发现, 并发压测线程32就比单线程时, 总体吞吐量高。

2)日志在备库上的执行, 就是图中备库上sql_thread更新数据(DATA)的逻辑。 如果是用单线程的话, 就会导致备库应用日志不够快, 造成主备延迟。

注:在官方的5.6版本之前, MySQL只支持单线程复制, 由此在主库并发高、 TPS高时就会出现严重的主备延迟问题。

备库多线程复制机制,都是要把上图中的sql_thread,拆成多个线程,也就是都符合下面的这个模型:

上图中,coordinator就是原来的sql_thread, 不过现在它不再直接更新数据了, 只负责读取中转日志和分发事务。 真正更新日志的, 变成了worker线程。 而work线程的个数, 就是由参数slave_parallel_workers决定的。

注:参数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中。

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

MySQL 5.5版本的并行复制策略


官方MySQL 5.5版本是不支持并行复制的。

常见并行策略:按表分发策略和按行分发策略。

按表分发策略

按表分发事务的基本思路:如果两个事务更新不同的表,它们就可以并行。因为数据是存储在表里的,所以按表分发,可以保证两个worker不会更新同一行。

当然如果有跨表的事务,还是要把两张表放在一起考虑,以保证事务逻辑的隔离性。按表分发规则如下:

从上图可以看到, 每个worker线程对应一个hash表, 用于保存当前正在这个worker的“执行队列”里的事务所涉及的表。 hash表的key是“库名.表名”, value是一个数字, 表示队列中有多少个事务修改这个表。

在有事务分配给worker时, 事务里面涉及的表会被加到对应的hash表中。 worker执行完成后, 这个表会被从hash表中去掉。

图3中, hash_table_1表示, 现在worker_1的“待执行事务队列”里, 有4个事务涉及到db1.t1表,有1个事务涉及到db2.t2表; hash_table_2表示, 现在worker_2中有一个事务会更新到表t3的数据。

假设在图中的情况下, coordinator从中转日志中读入一个新事务T, 这个事务修改的行涉及到表t1和t3。

现在用事务T的分配流程,看一下基于表的分配规则:

1)由于事务T中涉及修改表t1, 而worker_1队列中有事务在修改表t1, 事务T和队列中的某个事务要修改同一个表的数据, 这种情况我们说事务T和worker_1是冲突的。

2)按照这个逻辑, 顺序判断事务T和每个worker队列的冲突关系, 会发现事务T跟worker_2也冲突。

3)事务T跟多于一个worker冲突, coordinator线程就进入等待。

4)每个worker继续执行, 同时修改hash_table。 假设hash_table_2里面涉及到修改表t3的事务先执行完成, 就会从hash_table_2中把db1.t3这一项去掉。

5)这样coordinator会发现跟事务T冲突的worker只有worker_1了, 因此就把它分配给worker_1。

6)coordinator继续读下一个中转日志, 继续分配事务。

每个事务在分发的时候, 跟所有worker的冲突关系包括以下三种情况:

1)如果跟所有worker都不冲突, coordinator线程就会把这个事务分配给最空闲的woker。

2)如果只跟一个worker冲突, coordinator线程就会把这个事务分配给这个存在冲突关系的worker。

3)如果跟多于一个worker冲突, coordinator线程就进入等待状态, 直到和这个事务存在冲突关系的worker只剩下1个。

注:按表分发的方案, 在多个表负载均匀的场景里应用效果很好。 但是, 如果碰到热点表, 比如所有的更新事务都会涉及到某一个表的时候, 所有事务都会被分配到同一个worker中, 就变成单线程复制了。

按行分发策略

要解决热点表的并行复制问题, 就需要一个按行并行复制的方案。

按行复制的核心思路是: 如果两个事务没有更新相同的行, 它们在备库上可以并行执行。 显然, 这个模式要求binlog格式必须是row。

按行复制和按表复制的数据结构差不多, 也是为每个worker, 分配一个hash表。 只是要实现按行分发, 这时候的key, 就必须是“库名+表名+唯一键的值”。

但是, 这个“唯一键”只有主键id还是不够的, 我们还需要考虑下面这种场景, 表t1中除了主键,还有唯一索引a:

CREATE TABLE `t1` (
 `id` int(11) NOT NULL,
 `a` int(11) DEFAULT NULL,
 `b` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `a` (`a`)
) ENGINE=InnoDB;

insert into t1values(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5);

假设, 接下来我们要在主库执行这两个事务:

这两个事务要更新的行的主键值不同, 但是如果它们被分到不同的worker, 就有可能session B的语句先执行。 这时候id=1的行的a的值还是1, 就会报唯一键冲突。

因此, 基于行的策略, 事务hash表中还需要考虑唯一键, 即key应该是“库名+表名+索引a的名字+a的值”。

比如, 在上面这个例子中, 我要在表t1上执行update t1 set a=1 where id=2语句, 在binlog里面记录了整行的数据修改前各个字段的值, 和修改后各个字段的值。

因此, coordinator在解析这个语句的binlog的时候, 这个事务的hash表就有三个项:

1)key=hash_func(db1+t1+“PRIMARY”+2), value=2; 这里value=2是因为修改前后的行id值不变, 出现了两次。

2)key=hash_func(db1+t1+“a”+2), value=1, 表示会影响到这个表a=2的行。

3)key=hash_func(db1+t1+“a”+1), value=1, 表示会影响到这个表a=1的行。

相比于按表并行分发策略, 按行并行策略在决定线程分发的时候, 需要消耗更多的计算资源。 你可能也发现了, 这两个方案其实都有一些约束条件:

1)要能够从binlog里面解析出表名、 主键值和唯一索引的值。 也就是说, 主库的binlog格式必须是row。

2)表必须有主键。

3)不能有外键。 表上如果有外键, 级联更新的行不会记录在binlog中, 这样冲突检测就不准确。

对比按表分发和按行分发这两个方案的话, 按行分发策略的并行度更高。 不过, 如果是要操作很多行的大事务的话, 按行分发的策略有两个问题:

1)耗费内存。 比如一个语句要删除100万行数据, 这时候hash表就要记录100万个项。

2)耗费CPU。 解析binlog, 然后计算hash值, 对于大事务, 这个成本还是很高的。

所以, 在实现这个策略的时候会设置一个阈值, 单个事务如果超过设置的行数阈值(比如, 如果单个事务更新的行数超过10万行) , 就暂时退化为单线程模式, 退化过程的逻辑大概是这样的:

1)coordinator暂时先hold住这个事务。

2)等待所有worker都执行完成, 变成空队列。

3)coordinator直接执行这个事务。

4)恢复并行模式。

注:上述按表分发策略和按行分发策略是MySQL45讲作者自主研发。

MySQL 5.6版本的并行复制策略


官方MySQL5.6版本, 支持了并行复制, 只是支持的粒度是按库并行。

与按表分发策略和按行分发策略同理,按库分发策略的hash表里,key就是数据库名。

这个策略的并行效果,取决于压力模型。如果在主库上有多个DB,并且各个DB的压力均衡,使用该策略的效果会很好。

相比于按表和按行分发,按库分发策略有两个优势:

1)构造hash值的时候很快, 只需要库名; 而且一个实例上DB数也不会很多, 不会出现需要构造100万个项这种情况。

2)不要求binlog的格式。 因为statement格式的binlog也可以很容易拿到库名。

注1:如果主库上的表都放在同一个DB里面,这个策略就没有效果了。

注2:如果不同DB的热点不同,该策略也起不到并行的效果。如,一个是业务逻辑库,一个是系统配置库。

注3:理论上可以创建不同的DB, 把相同热度的表均匀分到这些不同的DB中, 强行使用这个策略。但由于需要特地移动数据, 所以这个策略用得并不多。

MariaDB的并行复制策略


MariaDB的并行复制策略特性:

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

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

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

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

2)commit_id直接写到binlog里面。

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

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

MariaDB的并行复制策略缺点:

1)它并没有实现“真正的模拟主库并发度”这个目标。 在主库上, 一组事务在commit的时候, 下一组事务是同时处于“执行中”状态的。

假设了三组事务在主库的执行情况, 你可以看到在trx1、 trx2和trx3提交的时候, trx4、 trx5和trx6是在执行的。 这样, 在第一组事务提交完成的时候, 下一组事务很快就会进入commit状态。主库并行事务执行效果:

2)并行过程中,如果同组有大事务,则需要等待大事务执行完成后才能继续。即容易被大事务推后退。

按照MariaDB的并行复制策略, 备库上的执行效果:

可以看到, 在备库上执行的时候, 要等第一组事务完全执行完成后, 第二组事务才能开始执行,这样系统的吞吐量就不够。

MySQL 5.7的并行复制策略


在MariaDB并行复制实现之后, 官方的MySQL5.7版本也提供了类似的功能, 由参数slaveparallel-type来控制并行复制策略:

1)配置为DATABASE, 表示使用MySQL 5.6版本的按库并行策略。

2)配置为 LOGICAL_CLOCK, 表示的就是类似MariaDB的策略。 不过, MySQL 5.7这个策略, 针对并行度做了优化。 这个优化的思路也很有趣儿。

问:同时处于“执行状态”的所有事务,是否可以并行?

答:不能。因为, 这里面可能有由于锁冲突而处于锁等待状态的事务。 如果这些事务在备库上被分配到不同的worker, 就会出现备库跟主库不一致的情况。但所有处于“commit状态”的事务是可以并行的,因为事务处于commit状态,表示已经通过了锁冲突的检验了。

其实, 不用等到commit阶段, 只要能够到达redo log prepare阶段, 就表示事务已经通过锁冲突的检验了。两阶段提交流程图:

因此, MySQL 5.7并行复制策略的思想是:

1)同时处于prepare状态的事务, 在备库执行时是可以并行的。

2)处于prepare状态的事务, 与处于commit状态的事务之间, 在备库执行时也是可以并行的。

讲binlog的组提交的时候, 介绍过两个参数:

  • binlog_group_commit_sync_delay参数, 表示延迟多少微秒后才调用fsync。
  • binlog_group_commit_sync_no_delay_count参数, 表示累积多少个事务以后才调用fsync。

这两个参数是用于故意拉长binlog从write到fsync的时间, 以此减少binlog的写盘次数。 在MySQL 5.7的并行复制策略里, 它们可以用来制造更多的“同时处于prepare阶段的事务”。 这样就增加了备库复制的并行度。

也就是说, 这两个参数, 既可以“故意”让主库提交得慢些, 又可以让备库执行得快些。 在MySQL 5.7处理备库延迟的时候, 可以考虑调整这两个参数值, 来达到提升备库复制并发度的目的。

MySQL 5.7.22的并行复制策略


在2018年4月份发布的MySQL 5.7.22版本里, MySQL增加了一个新的并行复制策略, 基于WRITESET的并行复制。

相应地, 新增了一个参数binlog-transaction-dependency-tracking, 用来控制是否启用这个新策略。 这个参数的可选值有以下三种:

  • COMMIT_ORDER, 表示的就是前面介绍的, 根据同时进入prepare和commit来判断是否可以并行的策略。
  • WRITESET, 表示的是对于事务涉及更新的每一行, 计算出这一行的hash值, 组成集合writeset。 如果两个事务没有操作相同的行, 也就是说它们的writeset没有交集, 就可以并行。
  • WRITESET_SESSION, 是在WRITESET的基础上多了一个约束, 即在主库上同一个线程先后执行的两个事务, 在备库执行的时候, 要保证相同的先后顺序。

注:为了唯一标识, 这个hash值是通过“库名+表名+索引名+值”计算出来的。 如果一个表上除了有主键索引外, 还有其他唯一索引, 那么对于每个唯一索引, insert语句对应的writeset就要多增加一个hash值。

虽然这和前面介绍的MySQL 5.5版本的按行分发的策略是差不多的。但MySQL官方的这个实现还是有很大的优势:

1)writeset是在主库生成后直接写入到binlog里面的, 这样在备库执行的时候, 不需要解析binlog内容(event里的行数据) , 节省了很多计算量。

2)不需要把整个事务的binlog都扫一遍才能决定分发到哪个worker, 更省内存。

3)由于备库的分发策略不依赖于binlog内容, 所以binlog是statement格式也是可以的。

注1:对于“表上没主键”和“外键约束”的场景, WRITESET策略也是没法并行的, 也会暂时退化为单线程模型。

注2:大事务不仅会影响到主库,也是造成备库复制延迟的主要原因之一。因此, 在平时的开发工作中, 我建议你尽量减少大事务操作, 把大事务拆成小事务。

小结:思考题


思考:假设一个MySQL 5.7.22版本的主库, 单线程插入了很多数据, 过了3个小时后, 我们要给这个主库搭建一个相同版本的备库。这时候, 你为了更快地让备库追上主库, 要开并行复制。 在binlog-transaction-dependencytracking参数的COMMIT_ORDER、 WRITESET和WRITE_SESSION这三个取值中, 你会选择哪一个呢?你选择的原因是什么? 如果设置另外两个参数, 你认为会出现什么现象呢?

答:选择WRITESET策略。

1)由于主库是单线程压力模式, 所以每个事务的commit_id都不同, 那么设置为COMMIT_ORDER模式的话, 从库也只能单线程执行。

2)WRITESET模式通过对比更新的事务是否存在冲突的行,可以并发执行。

3)由于WRITESET_SESSION模式要求在备库应用日志的时候, 同一个线程的日志必须与主库上执行的先后顺序相同, 也会导致主库单线程压力模式下退化成单线程复制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/639532.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

svg中path的直线命令使用

path路径 <path>元素是SVG基本形状中最强大的一个。可以使用它来创建线条&#xff0c;曲线&#xff0c;弧形等等。 另外&#xff0c;path只需要设定很少的点&#xff0c;就可以创建平滑流畅的线条&#xff08;比如曲线&#xff09;。虽然polygon元素也可以实现类似的效…

UPPAAL使用方法

UPPAAL使用方法 由于刚开始学习时间自动机及其使用方法&#xff0c;对UPPAAL使用不太熟悉&#xff0c;网上能找到的教程很少&#xff0c;摸索了很久终于成功实现一个小例子&#xff0c;所以记录一下详细教程。 这里用到的例子参考【UPPAAL学习笔记】1&#xff1a;基本使用示例…

linux-配置服务器之间 ssh免密登录

前言 在管理多台Linux服务器时,为了方便操作和自动化任务,实现服务器之间的SSH免密登录是非常有必要的。SSH免密登录可以避免每次远程连接时输入密码,大大提高效率。本文将详细介绍SSH免密登录的原理和实现步骤。 一、原理解释 SSH免密登录的实现依赖于SSH密钥对,主要是利用…

2.行为参数的演变过程

2.行为参数的演变过程 ​ 行为参数化是软件开发模式&#xff0c;可以处理频繁变更的需求。它让你把一个代码块准备好但不执行&#xff0c;以后可以被其他部分调用&#xff0c;也可以作为参数传递给另一个方法&#xff0c;推迟执行。这样&#xff0c;方法的行为就基于参数化的代…

O2OA(翱途)开发平台数据统计如何配置?

O2OA提供的数据管理中心&#xff0c;可以让用户通过配置的形式完成对数据的汇总&#xff0c;统计和数据分组展现&#xff0c;查询和搜索数据形成列表数据展现。也支持用户配置独立的数据表来适应特殊的业务的数据存储需求。本文主要介绍如何在O2OA中开发和配置统计。 一、先决…

03-ArcGIS For JavaScript结合ThreeJS功能

ArcGIS For JavaScript结合ThreeJS功能 概述three.js中功能实现externalRenderers&#xff08;4.28及以下版本&#xff09;RenderNode&#xff08;4.29版本&#xff09; 概述 ArcGIS For Javacript提供了一些对象可以支持加载webgl上下文信息&#xff0c;这里包括webgl编程的代…

汽车IVI中控开发入门及进阶(二十):显示技术之LCDC

TFT LCD=Thin Film Transistor Liquid Crystal Display LCDC=LCD Controller 薄膜晶体管液晶显示器(TFT LCD)控制器在驱动现代显示技术的功能和性能方面起着关键作用。它们充当屏幕后面的大脑,仔细处理数字信号,并将其转化为精确的命令,决定每个像素的行为,决定它们的…

Linux中gcc/g++的基本使用

目录 gcc/g的使用gcc/g是如何生成可执行文件的预处理编译汇编链接 库.o文件是如何与库链接的&#xff1f; debug版本和release版本 gcc/g的使用 在windows中&#xff0c;我们在VS中编写好了代码之后就可以直接在VS中对源码进行编译等操作后运行 而在Linux下&#xff0c;我们可…

【区域脑图论文笔记】BrainNetCNN:第一个专门为脑网络连接体数据设计的深度学习框架

【区域脑图论文笔记】BrainNetCNN&#xff1a;第一个专门为脑网络连接体数据设计的深度学习框架 信息概览与提炼采用的数据与结果数据集结果概览一眼 重点图与方法概览核心与优劣总结模型与实验论文方法E2E的理解E2N的理解N2G的理解三个卷积层设计的理解 论文实验与讨论 总结与…

差分约束题解

目录 注意点&#xff1a; 思路&#xff1a; SPFA和Dij的不同点&#xff1a; Dij: SPFA: AC代码&#xff1a; 扩展&#xff1a; 题目链接&#xff1a;【模板】差分约束 - 洛谷 注意点&#xff1a; 注意这一题不能用Dij&#xff0c;只能用SPFA 因为这样子才可以得出这个不…

【源码】AVATRADE多语言交易所/15国语言交易所/合约交易/期权交易/币币交易/申购/矿机/风控/前端wap/pc纯源码/带搭建教程

推荐AVATRADE多语言交易所/15国语言交易所/合约交易/期权交易/币币交易/申购/矿机/风控/前端wap/pc纯源码/带搭建教程 语言&#xff1a;15种语言 前端pcwap都是纯源码的 workerman启动有点问题&#xff0c;采集是正常的&#xff0c;wss不能推送。时好时坏&#xff0c;有时候…

树莓派开发需要安装哪些常用库

树莓派是一系列小型、低成本、高性能的单板计算机&#xff08;SBC&#xff09;&#xff0c;旨在促进编程、计算机科学和DIY电子项目。 从英国慈善机构树莓派基金会于 2012 年推出第一代树莓派开始&#xff0c;树莓派被广泛应用于各种项目&#xff0c;包括&#xff1a; 学习和教…

unreal engine 5.0.3 创建游戏项目

根据虚幻官网介绍&#xff0c;虚幻引擎5可免费用于创建线性内容、定制项目和内部项目。你可以免费用它开发游戏&#xff0c;只有当你的产品营收超过100万美元时&#xff0c;才收取5%的分成费用。所以目前国内也有许多游戏厂商在使用UE制作游戏。UE5源码也已开源&#xff0c;有U…

JavaScript表达式和运算符

表达式 表达式一般由常量、变量、运算符、子表达式构成。最简单的表达式可以是一个简单的值。常量或变量。例&#xff1a;var a10 运算符 运算符一般用符号来表示&#xff0c;也有些使用关键字表示。运算符由3中类型 1.一元运算符&#xff1a;一个运算符能够结合一个操作数&…

RFID技术在空调生产流程自动化中的前沿探索

RFID技术在空调生产流程自动化中的前沿探索 应用背景 目前经济环境下&#xff0c;由卖方市场转向买方市场&#xff0c;意味着小批量、多频率、个性化的生产模式日益成为制造业企业面临的一大难题&#xff0c;随着个性化需求的不断增长&#xff0c;大部分空调厂商都选择小批量…

云上聚智——移动云云服务器进行后端的搭建及部署

什么是移动云 移动云是指将移动设备和云计算技术相结合&#xff0c;为移动应用提供强大的计算和存储能力的服务模式。传统的移动应用通常在本地设备上进行计算和存储&#xff0c;而移动云将这些任务转移到云端进行处理。通过移动云&#xff0c;移动设备可以利用云端的高性能计算…

Go团队:Go是什么

2024年的Google I/O大会[1]如期而至。 这届大会的核心主旨毫无疑问是坚定不移的以AI为中心&#xff1a;Google先是发布了上下文长度将达到惊人的200万token的Gemini 1.5 Pro[2]&#xff0c;然后面对OpenAI GPT-4o的挑衅&#xff0c;谷歌在大会上直接甩出大杀器Project Astra[3]…

【加密与解密(第四版)】第十九章笔记

第十九章 外壳编写基础 这章主要是完成一个壳&#xff0c;之前这章看的次数比较多&#xff0c;这里仅仅记录一下关键点 19.1 外壳的结构 19.2 加壳主程序 流程&#xff1a;判断文件是否为PE格式、文件基本数据读入、附加数据的读取、输入表的处理、重定位表的处理、文件的压缩…

【嵌入式软件工程师面经】Socket,TCP,HTTP之间的区别

目录&#xff1a; 目录 目录&#xff1a; 一、Socket原理与TCP/IP协议 1.1 Socket概念&#xff1a; 1.2 建立Socket连接&#xff1a; 1.3 SOCKET连接与TCP/IP连接 二、HTTP连接&#xff1a; 2.1 HTTP原理 三、三者的区别和联系 前些天发现了一个巨牛的人工智能学习网站&#xf…

ICRA 2024: NVIDIA 联合多伦多大学、加州大学伯克利分校、苏黎世联邦理工学院等研究人员开发了精细操作的手术机器人

英伟达&#xff08;NVIDIA&#xff09;正与学术研究人员合作&#xff0c;研究手术机器人。 NVIDIA 联合多伦多大学、加州大学伯克利分校、苏黎世联邦理工学院和佐治亚理工学院的研究人员开发了 ORBIT-Surgical&#xff0c;一个训练机器人的模拟框架&#xff0c;可以提高手术团…