从库延迟案例分析

背景介绍

近来一套业务系统,从库一直处于延迟状态,无法追上主库,导致业务风险较大。从资源上看,从库的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_CLOCKslave_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
BEGINBEGIN
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
BEGINBEGIN
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
BEGINBEGINBEGIN
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社区 Gitee GitHub Bilibili

GreatSQL社区:

image

社区有奖建议反馈: https://greatsql.cn/thread-54-1-1.html

社区博客有奖征稿详情: https://greatsql.cn/thread-100-1-1.html

(对文章有疑问或者有独到见解都可以去社区官网提出或分享哦~)

技术交流群:

微信&QQ群:

QQ群:533341697

微信群:添加GreatSQL社区助手(微信号:wanlidbc )好友,待社区助手拉您进群。

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

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

相关文章

Python —— 简述

Houdini Python | 笔记合集 - 知乎 Houdini内置三大语言&#xff1a; 表达式&#xff0c;主要用于节点参数控制&#xff0c;可实现跨模块控制&#xff1b;vex&#xff0c;速度最快&#xff08;比表达式和Python快一个数量级&#xff09;&#xff0c;非常适合密集型计算环境&…

【React】Ant Design社区扩展库之分割面板:react-resizable-panels

主角&#xff1a;react-resizable-panels 简介&#xff1a;来之Ant Design官方文档社区精选组件 1、效果 2、环境 react-resizable-panels: ^2.0.16next: 14.1.3react: ^18 3、安装 # npm npm install react-resizable-panels# yarn yarn add react-resizable-panels# pnpm …

Docker学习笔记(二):在Linux中部署Docker(Centos7下安装docker、环境配置,以及镜像简单使用)

一、前言 记录时间 [2024-4-6] 前置文章&#xff1a;Docker学习笔记&#xff08;一&#xff09;&#xff1a;入门篇&#xff0c;Docker概述、基本组成等&#xff0c;对Docker有一个初步的认识 在上文中&#xff0c;笔者进行了Docker概述&#xff0c;介绍其历史、优势、作用&am…

《三》按钮---PushButton和信号槽机制

QPushButton按钮用法详解 按钮是 GUI 开发中最常用到的一种控件&#xff0c;作为一款著名的 GUI 开发框架&#xff0c;Qt 提供了很多种按钮&#xff0c;比如 QPushButton&#xff08;普通按钮&#xff09;、QRadioButton&#xff08;单选按钮&#xff09;、QToolButton&#x…

对LSTM的通俗易懂理解--可变权重

RNN的问题&#xff1a;长期依赖&#xff0c;即对短期的数据敏感&#xff0c;对比较远的长期数据不敏感&#xff0c;这是因为RNN隐藏状态权重在不同时刻是共享相同的&#xff0c;随着时间步的增加&#xff0c;梯度会指数级地衰减或者增长&#xff0c;导致梯度消失或者爆炸&#…

【黑马头条】-day06自媒体文章上下架-Kafka

文章目录 今日内容1 Kafka1.1 消息中间件对比1.2 kafka介绍1.3 kafka安装及配置1.4 kafka案例1.4.1 导入kafka客户端1.4.2 编写生产者消费者1.4.3 启动测试1.4.4 多消费者启动 1.5 kafka分区机制1.5.1 topic剖析 1.6 kafka高可用设计1.7 kafka生产者详解1.7.1 同步发送1.7.2 异…

配置vlan和vlan间路由、配置vlan的ip和vrrp、mstp和主次根

简单的通信实验 拓扑图&#xff1a; 1.配置vlan和链路聚合 Sw1 & sw2 undo info-center enable vlan batch 10 20 30 40 int eth-trunk 1 trunkport g 0/0/1 to 0/0/2 port link-type trunk port trunk allow-pass vlan 10 20 30 40 int g0/0/3 port link-type trunk p…

Unity 布局 HorizontalLayoutGroup 多行 换行

演示Gif&#xff1a; 现象: 子元素宽度不同&#xff0c;超出父元素后不会换行 GridLayout则是固定宽度也不能用&#xff0c; 需求 水平排版的同时&#xff0c;超出父级后换行 代码&#xff1a; 催更就展示[狗头]

Linux:Redis7.2.4的简单在线部署(1)

注意&#xff1a;我写的这个文章是以最快速的办法去搭建一个redis的基础环境&#xff0c;作用是为了做实验简单的练习&#xff0c;如果你想搭建一个相对稳定的redis去使用&#xff0c;可以看我下面这个文章 Linux&#xff1a;Redis7.2.4的源码包部署&#xff08;2&#xff09;-…

CSS 基础:设置背景的 5 个属性及简写 background 注意点

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端工具”&#xff0c;可获取 Web 开发工具合集 263篇…

给你的Qt软件加个授权

写在前面 环境&#xff1a; Win11 64位 VS2019 Qt5.15.2 核心思路&#xff1a; 将授权相关信息加密保存到License.txt中&#xff0c;软件运行时获取并解密授权信息&#xff0c;判断是否在限制期限内即可。 加解密部分使用第三方openssl库进行&#xff0c;因此需要手动在…

家庭网络防御系统搭建-虚拟机安装siem/securityonion网络连接问题汇总

由于我是在虚拟机中安装的security onion&#xff0c;在此过程中&#xff0c;遇到很多的网络访问不通的问题&#xff0c;通过该文章把网络连接问题做一下梳理。如果直接把securityonion 安装在物理机上&#xff0c;网络问题则会少很多。 NAT无法访问虚拟机 security onion虚拟…

多目标跟踪 | 基于anchor-free目标检测+ReID的实时一阶多类多目标跟踪算法实现

项目应用场景 面向多目标检测跟踪场景&#xff0c;项目采用 anchor-free 目标检测ReID 的实时一阶段多类多目标跟踪算法实现&#xff0c;效果嘎嘎好。 项目效果 项目细节 > 具体参见项目 README.md (1) 类别支持 1~10 object classes are what we need non-interest-…

SpringCloud学习(9)-GateWay网关-自定义拦截器

GateWay Filter详细配置说明 gateway Filter官网:Spring Cloud Gateway 作用&#xff1a; 请求鉴权异常处理记录接口调用时长统计 过滤器类别 全局默认过滤器&#xff1a;官网&#xff1a;Spring Cloud Gateway&#xff0c;出厂默认已有的&#xff0c;直接用&#xff0c;作…

Qt栅格布局的示例

QGridLayout * layoutnew QGridLayout;for(int i0;i<10;i){for(int j0;j<6;j){QLabel *labelnew QLabel(this);label->setText(QString("%1行%2列").arg(i).arg(j));layout->addWidget(label,i,j);}}ui->widget->setLayout(layout); 这样写程序会崩…

【vue】v-bind动态属性绑定

v-bind 简写:value <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><styl…

NC65 查询默认密码(sql)

NC65 使用sql查询设置的默认密码&#xff08;如果系统设置有&#xff09;&#xff1a; select * from sm_user_defaultpwd

深入理解图形处理器(GPU):加速人工智能和大数据计算的引擎

文章目录 1. 什么是GPU&#xff1f;2. GPU的工作原理3. GPU的应用领域4. GPU与CPU的比较参考与推荐 前言&#xff1a; 图形处理器&#xff08;GPU&#xff09;不再仅仅是用于图形渲染的硬件设备。如今&#xff0c;GPU已经成为加速人工智能、大数据计算和科学研究的关键引擎。本…

提高大型语言模型 (LLM) 性能的四种数据清理技术

原文地址&#xff1a;four-data-cleaning-techniques-to-improve-large-language-model-llm-performance 2024 年 4 月 2 日 检索增强生成&#xff08;RAG&#xff09;过程因其增强对大语言模型&#xff08;LLM&#xff09;的理解、为它们提供上下文并帮助防止幻觉的潜力而受…

故障诊断 | 基于LSTM的滚动轴承故障诊断

效果 概述 基于LSTM(长短期记忆网络)的滚动轴承故障诊断是一种利用深度学习技术来预测滚动轴承是否存在故障的方法。下面是一个基本的滚动轴承故障诊断的流程: 数据收集:首先,需要收集与滚动轴承相关的振动信号数据。这些数据可以通过传感器或振动监测系统获取。收集的数…