MySQL从库延迟 [Note] Multi-threaded slave statistics : seconds elapsed = 120; events assigned【转】

news/2025/1/15 16:34:15/文章来源:https://www.cnblogs.com/paul8339/p/18673344

背景介绍

近来一套业务系统,从库一直处于延迟状态,无法追上主库,导致业务风险较大。从资源上看,从库的 CPU、IO、网络使用率较低,不存在服务器压力过高导致回放慢的情况;从库开启了并行回放;在从库上执行 show processlist 看到没有回放线程阻塞,回放一直在持续;解析 relay-log 日志文件,发现其中并没大事务回放。

过程分析

现象确认

收到运维同事的反馈,有一套从库延迟的非常厉害,提供了 show slave status 延迟的截图信息

file

持续观察了一阵 show slave status 的变化,发现 pos 点位信息在不停的变化,Seconds_Behind_master 也是不停的变化的,总体趋势还在不停的变大。

资源使用

观察了服务器资源使用情况,可以看到占用非常低

file

观察从库进程情况,基本上只能看到有一个线程在回放工作

file

并行回放参数说明

在主库设置了 binlog_transaction_dependency_tracking=WRITESET

在从库设置了 slave_parallel_type=LOGICAL_CLOCK 和 slave_parallel_workers=64

error log 日志对比

从 error log 中取并行回放的日志进行分析

$ grep 010559 100werror3306.log | tail -n 3
2024-01-31T14:07:50.172007+08:00 6806 [Note] [MY-010559] [Repl] Multi-threaded slave statistics for channel 'cluster': seconds elapsed = 120; events assigned = 3318582273; worker queues filled over overrun level = 207029; waite
d due a Worker queue full = 238; waited due the total size = 0; waited at clock conflicts = 348754579743300 waited (count) when Workers occupied = 34529247 waited when Workers occupied = 768473697132002024-01-31T14:09:50.078829+08:00 6806 [Note] [MY-010559] [Repl] Multi-threaded slave statistics for channel 'cluster': seconds elapsed = 120; events assigned = 3319256065; worker queues filled over overrun level = 207029; waite
d due a Worker queue full = 238; waited due the total size = 0; waited at clock conflicts = 348851330164000 waited (count) when Workers occupied = 34535857 waited when Workers occupied = 768664198419002024-01-31T14:11:50.060510+08:00 6806 [Note] [MY-010559] [Repl] Multi-threaded slave statistics for channel 'cluster': seconds elapsed = 120; events assigned = 3319894017; worker queues filled over overrun level = 207029; waite
d due a Worker queue full = 238; waited due the total size = 0; waited at clock conflicts = 348943740455400 waited (count) when Workers occupied = 34542790 waited when Workers occupied = 76890229805500

上述信息的详细解释,可以参考 MTS 性能监控你知道多少

去掉了发生次数比较少的统计,显示了一些关键数据的对比

file

可以发现自然时间 120,回放的协调线程有 90 多秒由于无法并行回放而进入等待,有近 20 秒是由于没有空闲的 work 线程进入等待,折算下来协调线程工作的时间只有 10 秒左右。

并行度统计

众所周知,mysql 从库并行回放主要依赖于 binlog 中的 last_commmitted 来做判断,如果事务的 last_committed 相同,则基本上可以认为这些事务可以并行回放,下面从环境中获取一个 relay log 进行并行回放的大概统计

$ mysqlsqlbinlog --no-defaults 046638 |grep -o 'last_committed.*' | sed 's/=/ /g' | awk '{print $2}' |sort -n | uniq -c |awk 'BEGIN {print "last_commited group_count Percentage"} {count[$2]=$1
; sum+=$1} END {for (i in count) printf "%d %d %.2f%%\n", i, count[i], (count[i]/sum)*100|"sort -k 1,1n"}' | awk '{if($2>=1 && $2 <11){sum+=$2}} END {print sum}' 
235703
$ mysqlsqlbinlog --no-defaults 046638 |grep -o 'last_committed.*' | sed 's/=/ /g' | awk '{print $2}' |sort -n | uniq -c |awk 'BEGIN {print "last_commited group_count Percentage"} {count[$2]=$1
; sum+=$1} END {for (i in count) printf "%d %d %.2f%%\n", i, count[i], (count[i]/sum)*100|"sort -k 1,1n"}' | awk '{if($2>10){sum+=$2}} END {print sum}'
314694

上述第一条命令,是统计 last_committed 相同的事务数量在 1-10 个,即并行回放程度较低或者是无法并行回放,这些事务总数量为 235703,占 43%,详细解析并行回放度比较低的事务分布,可以看出这部分 last_committed 基本上都是单条的,都需要等待先序事务回放完成后,自己才能进行回放,这就会造成前面日志中观察到的协调线程等待无法并行回放而进入等待的时间比较长的情况

$ mysqlbinlog --no-defaults 046638 |grep -o 'last_committed.*' | sed 's/=/ /g' | awk '{print $2}' |sort -n | uniq -c |awk 'BEGIN {print "last_commited group_count Percentage"} {count[$2]=$1; sum+=$1} END {for (i in count) printf "%d %d %.2f%%\n", i, count[i], (count[i]/sum)*100|"sort -k 1,1n"}' | awk '{if($2>=1 && $2 <11) {print $2}}' | sort | uniq -c200863 117236 298 313 43 51 7

第二条命令统计 last_committed 相同的事务数量超过 10 个的总事务数,其数量为 314694,占 57%,详细解析了这些并行回放度比较高的事务,可以看到每一组是在 6500~9000 个事务数间

$ mysqlsqlbinlog --no-defaults 046638 |grep -o 'last_committed.*' | sed 's/=/ /g' | awk '{print $2}' |sort -n | uniq -c |awk 'BEGIN {print "last_commited group_count Percentage"} {count[$2]=$1
; sum+=$1} END {for (i in count) printf "%d %d %.2f%%\n", i, count[i], (count[i]/sum)*100|"sort -k 1,1n"}' | awk '{if($2>11){print $0}}' | column -t
last_commited  group_count  Percentage
1              7340         1.33%
11938          7226         1.31%
23558          7249         1.32%
35248          6848         1.24%
46421          7720         1.40%
59128          7481         1.36%
70789          7598         1.38%
82474          6538         1.19%
93366          6988         1.27%
104628         7968         1.45%
116890         7190         1.31%
128034         6750         1.23%
138849         7513         1.37%
150522         6966         1.27%
161989         7972         1.45%
175599         8315         1.51%
189320         8235         1.50%
202845         8415         1.53%
218077         8690         1.58%
234248         8623         1.57%
249647         8551         1.55%
264860         8958         1.63%
280962         8900         1.62%
297724         8768         1.59%
313092         8620         1.57%
327972         9179         1.67%
344435         8416         1.53%
359580         8924         1.62%
375314         8160         1.48%
390564         9333         1.70%
407106         8637         1.57%
422777         8493         1.54%
438500         8046         1.46%
453607         8948         1.63%
470939         8553         1.55%
486706         8339         1.52%
503562         8385         1.52%
520179         8313         1.51%
535929         7546         1.37%

last_committed 机制介绍

主库的参数 binlog_transaction_dependency_tracking 用于指定如何生成其写入二进制日志的依赖信息,以帮助从库确定哪些事务可以并行执行,即通过该参数控制 last_committed 的生成机制,参数可选值有 COMMIT_ORDER、WRITESET、SESSION_WRITESET。 从下面这段代码,很容易看出来三种参数关系:

  1. 基础算法为 COMMIT_ORDER
  2. WRITESET 算法是在 COMMIT_ORDER 基础上再计算一次
  3. SESSION_WRITESET 算法是在 WRITESET 基础上再计算一次

file

由于我的实例设置的是 WRITESET,因此关注 COMMIT_ORDER 算法和的 WRITESET 算法即可。

COMMIT_ORDER

COMMIT_ORDER 计算规则:如果两个事务在主节点上是同时提交的,说明两个事务的数据之间没有冲突,那么一定也是可以在从节点上并行执行的,理想中的典型案例如下面的例子

session-1session-2
BEGIN BEGIN
INSERT t1 values(1)  
  INSERT t2 values(2)
commit (group_commit) commit (group_commit)

但对于 MySQL 来说,group_commit 是内部行为,只要 session-1 和 session-2 是同时执行 commit,不管内部是否合并为 group_commit,两个事务的数据本质上都是没有冲突的;再退一步来讲,只要 session-1 执行 commit 之后,session-2 没有新的数据写入,两个事务依旧没有数据冲突,依然可以并行复制。

session-1session-2
BEGIN BEGIN
INSERT t1 values(1)  
  INSERT t2 values(2)
commit  
  commit

对于更多并发线程的场景,可能这些线程不能同时并行复制,但部分事务却可以。以如下一个执行顺序来说,在 session-3 提交之后,session-2 没有新的写入,那么这两个事务是可以并行复制的;而 session-3 提交后,session-1 又插入了一条新的数据,此时无法判定数据冲突,所以 session-3 和 session-1 的事务无法并行复制;但 session-2 提交后,session-1 之后没有新数据写入,所以 session-2 和 session-1 又可以并行复制。因此,这个场景中,session-2 分别可以和 session-1,session-3 并行复制,但 3 个事务无法同时并行复制。

session-1session-2session-3
BEGIN BEGIN BEGIN
INSERT t1 values(1) INSERT t2 values(1) INSERT t3 values(1)
INSERT t1 values(2) INSERT t2 values(2)  
    commit
INSERT t1 values(3)    
  commit  
commit    

WRITESET

实际上是 commit_order+writeset 的组合,会先通过 commit_order 计算出一个 last_committed 值,然后再通过 writeset 计算一个新值,最后取两者间的小值作为最终事务 gtid 的 last_committed。

在 MySQL 中,writeset 本质上是对 schema_name + table_name + primary_key/unique_key 计算的 hash 值,在 DML 执行语句过程中,通过 binlog_log_row 生成 row_event 之前,会将 DML 语句中所有的主键 / 唯一键都单独计算 hash 值,并加入到事务本身的 writeset 列表中。而如果存在无主键 / 唯一索引的表,还会对事务设置 has_missing_keys=true。

参数设置为 WRITESET,但是并不一定就能使用上,其限制如下

  1. 非 DDL 语句或者表具有主键或者唯一键或者空事务
  2. 当前 session 使用的 hash 算法与 hash map 中的一致
  3. 未使用外键
  4. hash map 的容量未超过 binlog_transaction_dependency_history_size 的设置 以上 4 个条件均满足时,则可以使用 WRITESET 算法,如果有任意一个条件不满足,则会退化为 COMMIT_ORDER 计算方式

file

具体 WRITESET 算法如下,事务提交时:

  1. last_committed 设置为 m_writeset_history_start,此值为 m_writeset_history 列表中最小的 sequence_number

  2. 遍历事务的 writeset 列表

    a 如果某个 writeset 在全局 m_writeset_history 中不存在,构建一个 pair<writeset, 当前事务的 sequence_number> 对象,插入到全局 m_writeset_history 列表中

    b. 如果存在,那么 last_committed=max (last_committed, 历史 writeset 的 sequence_number 值),并同时更新 m_writeset_history 中该 writeset 对应的 sequence_number 为当前事务值

  3. 如果 has_missing_keys=false,即事务所有数据表均包含主键或者唯一索引,则最后取 commit_order 和 writeset 两种方式计算的最小值作为最终的 last_committed 值

file

TIPS:基于上面 WRITESET 规则,就会出现后提交的事务的 last_committed 比先提交的事务还小的情况

结论分析

结论描述

根据 WRITESET 的使用限制,对 relay-log 及事务中涉及到的表结构进行了对比,分析单 last_committed 的事务组成发现如下两种情况:

  1. 单 last_committed 的事务中涉及到的数据和 sequence_number 存在数据冲突
  2. 单 last_committed 的事务中涉及到的表存在无主键的情况,而且这种事务特别多

从上面的分析中可以得出结论:无主键表的事务太多,导致 WRITESET 退化为 COMMIT_ORDER,而由于数据库为 TP 应用,事务都快速提交,多个事务提交无法保证在一个 commit 周期内,导致 COMMIT_ORDER 机制产生的 last_committed 重复读很低。从库也就只能串行回放这些事务,引起回放延迟。

优化措施

  1. 从业务侧对表做改造,在允许的情况下给相关表都添加上主键。
  2. 尝试调大参数 binlog_group_commit_sync_delay、binlog_group_commit_sync_no_delay_count 从 0 修改为 10000,由于特殊环境限制,该调整并未生效,不同的场景可能会有不同的表现。

Enjoy GreatSQL :)

关于 GreatSQL

GreatSQL 是适用于金融级应用的国内自主开源数据库,具备高性能、高可靠、高易用性、高安全等多个核心特性,可以作为 MySQL 或 Percona Server 的可选替换,用于线上生产环境,且完全免费并兼容 MySQL 或 Percona Server。

转自GreatSQL

从库延迟案例分析 - OSCHINA - 中文开源技术交流社区
https://my.oschina.net/GreatSQL/blog/11052043

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024,语音 AI 元年;2025,Voice Agent 即将爆发丨年度报告发布

围绕 Voice Agent 产品的研发、商业化和增长的完整生命周期,报告构建出一份 Voice Agent 产业生态全景图。 2024 年,AI 与实时互动技术的结合 达到了前所未有的高度。5 月, OpenAI 发布了 GPT-4o ,并展示了其对话功能,仿佛电影《HER》中的智能助手走入了现实生活。10 月,…

基恩士SR710+N-L20系列扫码枪EIP通讯 ( 汇川AM401-基恩士N-L20 )

第一步: 扫码枪设置 1, 基恩士扫码枪IP地址设置 2, 扫码枪EIP设置第二步: PLC设置及编程 1,EDS文件导入 2, EIP配置

预告:钓鱼系统

用于钓鱼演练的钓鱼系统钓鱼系统 数据统计 首页有数据统计,统计了各个模块的数据网页钓鱼 内置了一个钓鱼登录框可以查看被钓中的目标已经钓鱼页面浏览量,密码需要在服务器日志查看exe钓鱼 分为两个,一个是下载一个是运行 模拟的木马无实际危害,仅仅获取用户信息回传,可以…

git工作流区域

一、主要区域工作目录作用:本地系统中的文件夹 文件状态未跟踪:文件刚添加到工作目录,还没有被Git管理(还没有git add) 已跟踪:Git已经对这个文件进行过管理,Git在本地仓库中有这个文件的历史记录。未修改:该文件没有再做任何修改。 已修改:修改过了,但是没有使用git a…

为什么说开展信创数据库势在必行

我国发展信创数据库的原因 - 保障信息安全:数据库存储着大量关键数据,如政府机密、金融交易记录、企业商业机密等。国外数据库可能存在安全漏洞或被植入后门,对国家信息安全构成威胁。发展信创数据库可实现自主可控,从根源上保障数据安全,降低安全风险。 - 减少技术依赖:…

20221320冯泰瑞《密码系统设计》第十二周

20221320冯泰瑞《密码系统设计》第十二周 学习内容Head First C 嗨翻C语言第12章 课程 mindmapAI 对学习内容的总结 要求让AI(kimi,元宝等)阅读学习内容并进行总结,教材内容可以使用微信读书或者云班课电子教材总结 《Head First C》第十二章的内容主要介绍了如何在C语言中…

20221320冯泰瑞《密码系统设计》第十一周

20221320冯泰瑞《密码系统设计》第十一周 学习内容Head First C 嗨翻C语言第11章 课程 mindmapAI 对学习内容的总结 要求让AI(kimi,元宝等)阅读学习内容并进行总结,教材内容可以使用微信读书或者云班课电子教材总结 《Head First C》第十一章的内容主要介绍了C语言中网络编…

深入理解第一范式(1NF):数据库设计中的基础与实践

title: 深入理解第一范式(1NF):数据库设计中的基础与实践 date: 2025/1/15 updated: 2025/1/15 author: cmdragon excerpt: 在关系型数据库设计中,规范化是确保数据一致性和减少冗余的重要步骤。第一范式(1NF)作为规范化的基础,要求每个表都应遵循数据的原子性及唯一性…

GaussDB技术解读——GaussDB架构介绍之集群管理层(CM)关键技术方案

GaussDB Kernel V5 集群管理层关键模块如下。图4 集群管理层组件设计图 CM 组件提供了四种服务 CM Agent, CM Server, OM Monitor, cm_ctl,与各类实例服务组件(CN, DN, GTM 等)一起构成了整个数据库集群系统。 cm_ctl 通过命令行执行集群的启动、停止、状态查询、主备倒换、…

GaussDB技术解读——GaussDB架构介绍之OM运维管理关键技术方案

​ GaussDB Kernel V5 OM运维管理关键模块如下。OM 运维主要功能有: 安装 升级 节点替换 扩容、缩容 自动告警 巡检 备份恢复、容灾 日志分析系统 在华为云的部署模式下,OM相关组件部署示意图如下: 图7 华为云OM运维管理 用户登录华为云Console,访问GaussDB Kernel V5的管控…

通义发布语音模型 MinMo:全双工、多口音;MiniCPM-o :端侧 GPT-4o 级视觉、语音、多模态实时流式大模型

开发者朋友们大家好:这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文章 」、「有看点的 会议 」,但内容仅代表编辑…

部署 Browser-Use WebUI + DeepSeek 实现浏览器AI自动化

一、安装部署 1.安装 python3.11 或以上版本2.安装browser-use pip install browser-use3.安装 Playwright playwright install4.安装项目依赖 pip install langchain-google-genai==2.0.8 pip install pyperclip==1.9.0 pip install gradio==5.9.1 pip install langchain-olla…