Mysql备库为什么会延迟几个小时
导致备库延迟的原因。偶发性查询、备份,备库延迟影响分钟级,能追上来。
备库执行日志的速度持续低于主库生成日志的速度,延迟小时级别。压力持续高主库来说,永远都追不上
图 1 主备流程图
1、备库并行复制能力
黑色的两个箭头:写入主库(并行度高),备库上 sql_thread 执行中转日志(relay log)。
主库:,各种锁影响并发度。支持行锁,除极端场,并发度好。并发压测线程 32 就比单线程时,总吞吐量高。
备库: sql_thread 更新数据 (DATA) 的逻辑。单线程主备延迟(5.6 之前),主库并发高、TPS 高严重主备延迟
图 2 多线程模型
2、复制机制:sql_thread拆成多个线程
coordinator 就是sql_thread, 不直接更新,只读中转日志和分发事务。真正更新日志worker 线程。个数slave_parallel_workers 8~16 之间最好(32 核物理机),备库提供读查询,不能把 CPU 都吃光。
3、coordinator 分发两个基本要求:
不能更新覆盖。更新同一行两个事务,分发同一worker 中。
例:第二个比第一个事务先执行。主、备执行顺序相反,不一致
同一事务放同一个 worker 中。
例:事务更新了表 t1 、2 各一行,分到不同 worker ,最终结果主备一致的, t1 执行完成瞬间,备库上有一个查询,看到事务“更新了一半的结果”,破坏隔离性。
一、MySQL 5.5 并行复制策略
不支持并行复制的。备库单线程复制。
1.1按表分发策略
两个事务更新不同表,可并行。如是跨表事务,放一起考虑。
图 3 按表并行复制程模型
每个 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 的分配流程,看分配规则。
由于事务 T 中涉及修改表 t1,worker_1 队列中有事务在修改表 t1,事务 T 和队列中的某个事务要修改同一个表的数据,冲突。
顺序判断事务 T 和每个 worker 队列的冲突关系,事务 T 跟 worker_2 也冲突。
T 跟多于一个 worker 冲突,coordinator 等待。
每个 worker 继续执行,同时修改 hash_table。假设 hash_table_2里面涉及到修改表 t3 的事务先执行完成,从 hash_table_2中把 db1.t3 这一项去掉。
冲突的 worker 只有 worker_1 了,因此就把它分配给 worker_1。
coordinator 读下一个中转日志,分配事务。
worker 冲突关系包括以下三种情况:
跟所有 worker 都不冲突,coordinator 分配给最空闲woker;
跟多于一个 worker 冲突,coordinator 等待状态,直到只剩1 个;
只跟一个 worker 冲突,分配给这个 worker。
负载均匀效果好。热点表,涉及某一个表的时候,所有事务都会被分配到同一个 worker 中,单线程复制。
1.2按行分发策略
没更新相同行,备库可并行。 binlog 格式 row。
这时候,我们判断一个事务 T 和 worker 是否冲突,用的就规则就不是“修改同一个表”,而是“修改同一行”。
数据结构差不多,为每个 worker, hash 表。key,“库名 + 表名 + 唯一键值”。
唯一键:除了主键,还有唯一索引 a:主库执行这两个事务:
图 4 唯一键冲突示例
更新的行主键值不同,分到不同的 worker,B 先执行。 id=1 行 a 值还是 1,唯一键冲突。
因此,基于行的策略,事务 hash 表中还需要考虑唯一键, key “库名 + 表名 + 索引 a 的名字 +a 的值”。
表 t1 上执行 update t1 set a=1 where id=2 语句, binlog 记录行修改前后各个字段值。
coordinator在解析这个语句的 binlog 时,hash 表三个项:
key=hash_func(db1+t1+“PRIMARY”+2), value=2; 修改前后行 id 值不变,出现两次
key=hash_func(db1+t1+“a”+2), value=1,影响表 a=2 行
key=hash_func(db1+t1+“a”+1), value=1,影响表 a=1 行
按行并行,消耗更多计算资源。约束条件:
从 binlog 里解析出表名、主键值和唯一索引的值。主库 binlog 格式必须row;
必须有主键;
不能有外键。级联更新行不记录 binlog 中,冲突检测不准确。
按行并行度高。大事务的话,两个问题:
耗内存。删除 100 万行, hash 表记录 100 万项。
耗CPU。解析 binlog,计算 hash 值,成本高。
设置一个阈值,单个事务如果超过设置的行数阈值(比如,如果单个事务更新的行数超过 10 万行),退化为单线程模式:
coordinator 暂时 hold 住事务;
所有 worker 执行完,成空队列;
coordinator 直接执行这个事务; 恢复并行模式。
二、MySQL 5.6 版本并行复制策略
并行复制,按库并行。理解了上面介绍的按表分发策略和按行分发策略,你就理解了,用于决定分发策略的 hash 表里,key 就是数据库名。
取决于压力模型。多个 DB压力均衡,效果好。
优势:
构造 hash 值快,只要库名;实例上 DB 数不多,不会出现需要构造 100 万个项这种情况。
不要求 binlog 格式。statement 格式binlog 很容易拿到库名。
没效果:主库上的表都放在同一个 DB 里面,;不同 DB 热点不同,一个是业务逻辑库,一个是系统配置库
创建不同的 DB,把相同热度的表均匀分到这些不同的 DB 中,强行用。由于需要特地移动数据,用得并不多。
三、MariaDB 的并行复制策略
在第 23 篇文章中, redo log 组提交 (group commit) 优化, MariaDB 并行复制就是这个特性:
同一组里提交的事务,不修改同一行;
主库上并行,备库也可。
MariaDB 是这么做的:
组里一起提交事务,相同commit_id
commit_id 直接写binlog 里;
传备库时,相同 commit_id 分发多个 worker 执行;
执行完,coordinator 取下一批,commit_id+1。
之前都是“分析 binlog,拆分到 worker”上。MariaDB “模拟主库并行模式”。
问题:备库没真正并行。主库trx1、trx2 和 trx3 提交时,trx4、trx5 和 trx6 在执行的。提交完,下一组很快 commit
图 5 主库并行事务
MariaDB 并行复制策略,备库上执行如图 6
图 6 MariaDB 并行复制,备库并行效果
备库上,第一组完成,第二组才开始,吞吐量不够。
容易被大事务拖后腿。trx2超大事务,备库trx1 和 trx3 执行完成后,只能等 trx2完成,只有worker 工作,浪费。
四、MySQL 5.7 的并行复制策略
类似功能,参数slave-parallel-type 控制并行复制策略:
DATABASE, 5.6 并行策略;
LOGICAL_CLOCK,MariaDB 。做优化
“执行状态”所有事务,不能同时并行,锁冲突而等待,备库分配不同worker,不一致。
图 7 两阶段提交细化过程图
redo log prepare、 commit 状态,表示已通过锁冲突。并行思想:
1. 同时prepare 状态,备库可并行;
2. prepare 、 commit 之间,备库也可并行。
binlog 组提交两个参数,主库提交慢,让备库快。提升备库复制并发度:
1. binlog_group_commit_sync_delay 延迟多少微秒后才调用fsync;
2. binlog_group_commit_sync_no_delay_count 累积多少次调用 fsync。
五、MySQL 5.7.22 并行复制策略
基于WRITESET 并行复制。增加binlog-transaction-dependency-tracking控制是否启用新策略。参数三种:
COMMIT_ORDER,同时进入 prepare 和 commit 判断可否并行
WRITESET,更新每行,计算 hash 值,组成集合 writeset。两个事务没有操作相同的行,writeset 没交集,可并行。
WRITESET_SESSION,WRITESET 多了约束,主库先后执行两事务,备库相同顺序。
唯一标识 hash 值:“库名 + 表名 + 索引名 + 值”。还有其他唯一索引,每个唯一索引,insert 对应 writeset 多增加 hash 值。
优势:
1. writeset 主库生成后写入binlog 面,备库不需解析 binlog(event 里的行数据),省计算量;
2. 不需扫一遍binlog 决定分发到哪个 worker,省内存;
3. 备库分发策略不依赖binlog ,statement 也可
通用有保证。“表上没主键”和“外键约束”场景,WRITESET 策略没法并行,暂时退化为单线程
小结
MySQL各种多线程复制策略。不同策略优缺点
为什么要有多线程复制呢?单线程复制能力低,更新压力大主库,备库追不上主库。现象:备库seconds_behind_master 值越来越大
大事务不仅会影响主库,备库复制延迟。建议大事务拆小
MySQL5.7 备库并行策略,修改binlog,并不是向上兼容的,在主备切换、版本升级的时候需要把这个因素也考虑进去。
思考题
MySQL 5.7.22版本主库,单线程插入很多,3 小时后,给主库搭相同备库
更快追上主库,并行复制。binlog-transaction-dependency-tracking 参数 COMMIT_ORDER、WRITESET 和WRITE_SESSION 选择哪个?原因是?另外两个现象?
WRITESET。其他两个单线程。
评论1
同行更新几个事务, commit_id 相同,备库并行执行不一致?
同一行事务不可能同时commit。
原文链接: https://www.yukx.com/bingningm/article/details/1789.html 优科学习网Mysql备库为什么会延迟几个小时
-
mysql只支持一种join算法:Nested-LoopJoin(嵌套循环连接),但Nested-LoopJoin有三种变种:SimpleNested-LoopJoin,IndexNested-LoopJoin,BlockNested-LoopJoin(简单-索引-缓冲区)原理:1.SimpleNe
-
redis是一个内存数据库,一旦断电或服务器进程退出,内存数据库中的数据将全部丢失,所以需要redis持久化 redis持久化就是把数据保存在磁盘上,利用永久性存储介质将数据保存,在特定的时间将保存的数据进行恢复的工作机制redis提供两种持久化机制RDB:存储数据结果,关注点在数据AOF:存储操作
-
通过SQL的执行过程来介绍MySQL的基础结构. 首先有一个user_info表,表里有一个id字段,执行下面这条查询语句:Select * form user_info where i
-
索引(Index)是帮助MySQL高效获取数据的数据结构,索引的目的在于提高查询效率,就像字典和书籍的目录一样,有了目录,可以帮助你快速查找你需要的内容。可以理解为一个排好序的快速查找数据结构。也就是
-
说到数据库事务,大家脑子里一定很容易蹦出一堆事务的相关知识,如事务的ACID特性,隔离级别,解决的问题(脏读,不可重复读,幻读)等等,但是可能很少有人真正的清楚事务的这些特性又是怎么实现的,为什么要有四个隔离级别。今天我们就先来聊聊MySQL中事务的隔离性的实现原理,后续还会继续出文章分析其他特性的
-
前面我们系统了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块。相信你还记得,一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后到达存储引擎。那么,一条更新语句