在MySQL的默认事务隔离级别——读已提交(Read Committed, RC)中,开发者普遍认为不会出现间隙锁(Gap Lock)。这一认知源于RC级别的设计原则:仅通过行锁确保已提交数据的可见性,而将幻读问题交由应用层处理。然而,近期多个生产环境却报告了反常现象——RC级别下竟触发了Gap Lock!这不仅导致事务意外阻塞,更动摇了我们对隔离级别底层行为的理解。

问题来源

“mysql RC 隔离级别也会出现gap 锁吗?我们生产环境是RC 隔离级别,出现了gap 锁导致死锁咯 ”? 上一周同事突如其来的问题彻底把我问懵了。

其实一直以来我也是认为只有RR隔离级别才会出现的,甚至我找到曾有人就这个问题给mysql 团队提了个bug ,并且mysql 团队也认为是个bug。那为啥现在RC 也会出现,甚至RU 级别也会出现呢。。我来盘下到底是怎么回事

问题背景

事情经过是这样子的,上周我们生产环境报了个死锁的问题,是并发执行insert into ... on duplicate key update 的时候报的一个死锁。死锁的日志是这样子的

trx id 679250 lock_mode X locks gap before rec insert intention waiting

gap lock 阻塞了各自的的insert intention lock 。一眼看去这个是老生常谈的死锁现象了。慢着,我们生产环境是RC 隔离级别,一连串的疑问冒出来:RC 隔离级别怎么会出现gap lock 呢?gap lock 不是在RR隔离级别下为了解决幻读而存在的吗?直接颠覆了我的认知,不死心查几次生产环境的事务隔离级别确认都是RC 隔离级别。

难道我记错了吗?登录mysql官网,下面是官网的描述:

image.png

虽然说gap lock 可以通过改变为RC 进行禁用,但是依然在外键和唯一键的时候会用到gap lock。 um um 确实是官方说是会产生的,但是依然不明白为啥会用gap lock 呢?

网上找到一个网友跟我一样,因为这个问题曾经给mysql 提了一个bug bug73170

神奇的是mysql 当时还当成bug 修复了,但是导致二级索引的唯一键失效,又revert 掉这个fix bug 68021

似乎看起来,mysql 团队也曾经认为这是一个bug ,只是由于实现难度解决不了还是继续使用了gap lock

Anway 先重现死锁,再一步一步分析为啥唯一键的检查需要用到gap lock,为什么mysql 团队没有去掉它

问题重现

根据我同事提供的重现sql.

第一步:

CREATE TABLE `test2` ( `id` int(11) NOT NULL AUTO_INCREMENT, `code` int(11) NOT NULL, `other` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `code` (`code`) ) ENGINE=InnoDB ; TRUNCATE table test2; insert ignore into test2 (id,code, other) values(1,1,1),(3,3,3),(5,5,5);

现在数据库的数据是这样子的

idcodeother
111
333
555

第二步session1 

begin; insert into test2(code, other) values (3, 4) on duplicate key update other = VALUES(other); 数据库已经存在一个3的值,所以这里会冲突并且执行更新(这里的冲突很重要,是重现问题的关键)

第三步session2:

begin; insert into test2(code, other) values (5, 6) on duplicate key update other = VALUES(other); 数据库已经存在一个5的值,所以这里会冲突并且执行更新(这里的冲突很重要,是重现问题的关键)

以上正常执行,但是问题来了,当我在session2 继续插入(2,2)的时候,被锁阻塞住了,why? 数据库中有没有这条记录和我冲突,为啥要给我锁住,而且我是RC 隔离级别,可以允许幻读的存在,为啥给我加个gap lock?

session2: insert into test2(code, other) values (2, 2) on duplicate key update other = VALUES(other); 这个时候这个语句被阻塞了

第四步session1:

insert into test2(code, other) values (4, 4) on duplicate key update other = VALUES(other)

这个时候死锁产生了,是不是觉得很奇怪,不管是session 2 插入的(2,2)还是session1 插入的(4,4)他们在数据库中都不存在,理论上都应该可以正常执行,但实际上却阻塞了,这不是导致并发性能下降了吗?锁粒度过大了呢?

执行show engine innodb status; 看下死锁日志

image.png

从死锁日志可以看到插入意向锁是被对方的gap lock 阻塞住导致的死锁

问题分析

二级唯一索引的

俗话说的好,你要解决一个问题,你得先去了解它,我们看看二级索引的唯一键是怎么实现的

find the B-tree page in the secondary index you want to insert the value to assert the B-tree page is latched equal-range = the range of records in the secondary index which conflict with your value if(equal-range is not empty){ release the latches on the B-tree and start a new mini-transaction for each record in equal-range lock gap before it, and the record itself (this is what LOCK_S does) also lock the gap after the last(equal-range) also (before Bug #32617942 was fixed) lock the record after last(equal-range) once you are done with all of the above, find the B-tree page again and latch it again } insert the record into the page and release the latch on the B-tree page.

可以看到在二级唯一索引插入record 的时候, 分成了两个阶段

  1. 判断当前的物理记录上是否有冲突的record(delete mark 为不冲突)
  2. 如果没有冲突, 那么可以执行插入操作

这里在第一步 和 第二步 之间必须有锁来保证, 否则第一步 判断没有冲突可以插入的时候, 但是在第一步和第二步 之间另外一个事务插入了一个冲突的record, 那么第二步 再插入的时候其实是冲突了.

所以当前的实现如果gap 上存在至少一个相同的record(包括删除但是还没被回收的记录,因为删除只是做了个删除的墓碑标识,后面再回收), 那么需要给整个range 都加上gap X lock, 加了gap X lock 以后就可以禁止其他事务在这个gap 区间插入数据, 也就是通过lock 来保证第一步和第二步的原子性.

假设在code 这个唯一索引的数据是这样子的,总共有两个数据页,page1通过point 指针指向下一个数据页page2。红色带有delete mark 是代表这个数据已经被删除了,由于还没有给purge线程回收,因此还是在page 上,只是做了个删除的墓碑标识。绿色代表是正常的数据

image.png

现在我们有两个线程分别执行以下语句

sesson1: insert into test2(id,code, other) values (4,3, 4) on duplicate key update other = VALUES(other);

sesson2: insert into test2(id,code, other) values (12,3, 12) on duplicate key update other = VALUES(other);

session 1 执行第一个步判断code 唯一索引上找到有相同value 的记录 <3,3 delete mark>,<3,10 delete mark>,<3,11 delete mark>,<3,18 delete mark>,然后分别给他们加上next-key 锁。

最后还得再<5,5> 上增加gap 锁(假如这个5,5变成很大,那么意味着锁的gap 会非常大,影响并发性能),以防止<3,19>之后的数据被插入。到这一步是没有冲突的,因为这些值都是已经被删除的,插进去后不会违背唯一索引

如果在session 1 在第一阶段和第二阶段中间,session2 并发执行,那么第一阶段也会跟session 1 一样执行,都加上gap lock。因此后面他们两个人的插入都会失败,成功避免他们都成功来导致最终的数据不一致的问题。当然也就引入了死锁的

这个时候,你可能会说,如果我只是加数据上加锁S的行锁不是更好吗?这样就可以避免锁的范围太大,导致并发低下的问题。

session 1 执行第一个步判断code 唯一索引上找到有相同value 的记录 <3,3 delete mark>,<3,10 delete mark>,<3,11 delete mark>,<3,18 delete mark>,然后分别给他们加上s锁。

session 2 并发执行,也分别给他们加上s 锁,这个时候是不冲突的。他们两个都认为数据库没有这个记录,最后他们都插入成功。最终就违反了数据库的唯一键规则,这也就是mysql 团队修复了之前说bug 后带来的问题,因此有立马revert 了,直到今天都一直保留这个RC 隔离级别依然出现gap lock 的方式来保证唯一的正确性

image.png

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

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

相关文章

恢复MacOS 26系统后台的动作命令

1、终端 输入 sudo mkdir -p /Library/Preferences/FeatureFlags/Domain回车后输入mac解锁密码。 2、输入强制关闭命令 sudo defaults write /Library/Preferences/FeatureFlags/Domain/SpotlightUI.plist SpotlightPlus -dict Enabled -bool false它会“强制关闭 Spotlight…

01-JS资料

JS数据类型 var str abc; var num 123; var bool true; var und undefined; var n null; var arr[x,y,z]; var obj {}; var fun function() {}; console.log(typeof str); //string console.log(typeof num); //number console.log(typeof bool); //boolean consol…

学习日记-day34-6.20

知识点&#xff1a; 1.快速入门 知识点 核心内容 重点 IOC容器创建 通过ClassPathXmlApplicationContext加载XML配置文件创建容器&#xff0c;关联beans.xml 容器与配置文件的绑定关系&#xff08;多配置文件支持&#xff09; Bean获取方式 1. getBean(String id)返回…

如何使用 neptune.ai 优化模型训练期间的 GPU 使用率

GPU 可以大大加速深度学习模型的训练&#xff0c;因为它们专门用于执行神经网络核心的张量运算。 由于 GPU 是昂贵的资源&#xff0c;因此充分利用它们至关重要。GPU 使用率、内存利用率和功耗等指标可以洞悉资源利用率及其改进潜力。提高 GPU 使用率的策略包括混合精度训练、优…

腾讯混元3D制作简单模型教程-1

腾讯混元3D制作简单模型的零门槛教程,涵盖新手快速入门与进阶操作,结合官方工具特性及行业实践,分为两个核心板块: 🎯 一、新手零门槛:5分钟生成可打印模型(适合完全小白) 通过腾讯元宝APP的“3D角色梦工厂”功能,无需任何建模基础: 上传照片 打开腾讯元宝APP → …

一个库,比如kott_tinymce ,想把的依赖库从kotti升级到kotti2 ,请问我是不是查找替换,把所有的kotti字符替换成kotti2就行了?

一个库&#xff0c;比如kott_tinymce ,想把的依赖库从kotti升级到kotti2 &#xff0c;请问我是不是查找替换&#xff0c;把所有的kotti字符替换成kotti2就行了&#xff1f; kotti和kotti2的包结构、模块路径、接口完全一样&#xff0c;除了import kotti 变成kotti2 如果 kotti…

企业实践 | 银河麒麟KylinOS-V10(SP3)高级服务器操作系统基础安装指南

前言&#xff1a;国产操作系统的崛起与实践背景 在国产化浪潮与信息技术自主可控的大背景下&#xff0c;银河麒麟操作系统作为国产操作系统的代表之一&#xff0c;正逐步成为企业级应用的重要选择。本文将详细介绍银河麒麟高级服务器操作系统V10 SP3版本的基础知识与安装实践&…

Ubuntu 一键安装 ROS

Ubuntu 一键安装 ROS 安装命令如下&#xff1a; wget http://fishros.com/install -O fishros && . fishros 指令执行后&#xff0c;显示log如下图&#xff1a; 之后根据不同的系统安装对应的ros版本即可。

深度学习——基于卷积神经网络实现食物图像分类【4】(使用最优模型)

文件目录 引言一、环境准备二、数据预处理训练集预处理说明&#xff1a;验证集预处理说明&#xff1a; 三、自定义数据集类四、设备选择五、CNN模型构建六、模型加载与评估1. 加载预训练模型2. 准备测试数据3. 测试函数4. 计算准确率 七、完整代码八、总结 引言 本文将详细介绍…

C++基础算法————并查集

C++并查集详解与实战指南 一、引言 并查集(Union-Find)是一种高效的数据结构,用于处理一些不相交集合的合并与查询问题。它在图论、社交网络、网络连通性等领域有广泛的应用。并查集的核心思想是通过一个数组来记录每个元素的父节点,从而将元素组织成若干棵树,每棵树代表…

系统性能优化的关键手段

系统性能的提升方向 服务器并发处理能力&#xff1a;通过优化内存管理策略、选择合适的连接模式&#xff08;长连接或短连接&#xff09;、改进 I/O 模型&#xff08;如 epoll、IOCP&#xff09;、以及采用高效的服务器并发策略&#xff08;如多线程、事件驱动等&#xff09;&a…

httpclient实现http连接池

HTTP连接池是一种优化网络通信性能的技术&#xff0c;通过复用已建立的TCP连接减少重复握手开销&#xff0c;提升资源利用率。以下是关键要点&#xff1a; 核心原理与优势 ‌连接复用机制‌ 维护活跃连接队列&#xff0c;避免每次请求重复TCP三次握手/SSL协商&#xff0c;降低…

广义焦点丢失:学习用于密集目标检测的合格和分布式边界盒之GFL论文阅读

摘要 一阶段检测器通常将目标检测形式化为密集的分类与定位(即边界框回归)问题。分类部分通常使用 Focal Loss 进行优化,而边界框位置则在狄拉克δ分布下进行学习。最近,一阶段检测器的发展趋势是引入独立的预测分支来估计定位质量,所预测的质量可以辅助分类,从而提升检…

Real-World Deep Local Motion Deblurring论文阅读

Real-World Deep Local Motion Deblurring 1. 研究目标与实际问题意义1.1 研究目标1.2 实际问题1.3 产业意义2. 创新方法:LBAG模型与关键技术2.1 整体架构设计2.2 关键技术细节2.2.1 真实模糊掩码生成(LBFMG)2.2.2 门控块(Gate Block)2.2.3 模糊感知补丁裁剪(BAPC)2.3 损…

【Docker基础】Docker镜像管理:docker commit详解

目录 引言 1 docker commit命令概述 1.1 什么是docker commit 1.2 使用场景 1.3 优缺点分析 2 docker commit命令详解 2.1 基本语法 2.2 常用参数选项 2.3 实际命令示例 2.4 提交流程 2.5 步骤描述 3 docker commit与Dockerfile构建对比 3.1 构建流程对比 3.2 对…

可调式稳压二极管

1.与普通稳压二极管的比较&#xff1a; 项目普通稳压二极管可调式稳压二极管&#xff08;如 TL431&#xff09;输出电压固定&#xff08;如5.1V、3.3V&#xff09;可调&#xff08;2.5V ~ 36V&#xff0c;取决于外部分压&#xff09;精度低&#xff08;5%~10%&#xff09;高&a…

Kafka使用Elasticsearch Service Sink Connector直接传输topic数据到Elasticsearch

链接&#xff1a;Elasticsearch Service Sink Connector for Confluent Platform | Confluent Documentation 链接&#xff1a;Apache Kafka 一、搭建测试环境 下载Elasticsearch Service Sink Connector https://file.zjwlyy.cn/confluentinc-kafka-connect-elasticsearch…

讯方“教学有方”平台获华为昇腾应用开发技术认证!

教学有方 华为昇腾应用开发技术认证 权威认证 彰显实力 近日&#xff0c;讯方技术自研的教育行业大模型平台——“教学有方”&#xff0c;成功获得华为昇腾应用开发技术认证。这一认证不仅是对 “教学有方” 平台技术实力的高度认可&#xff0c;更标志着讯方在智慧教育领域的…

保护你的Electron应用:深度解析asar文件与Virbox Protector的安全策略

在现代软件开发中&#xff0c;Electron框架因其跨平台特性而备受开发者青睐。然而&#xff0c;随着Electron应用的普及&#xff0c;如何保护应用中的核心资源文件——asar文件&#xff0c;成为了开发者必须面对的问题。今天&#xff0c;我们将深入探讨asar文件的特性&#xff0…

端口安全配置示例

组网需求 如图所示&#xff0c;用户PC1、PC2、PC3通过接入设备连接公司网络。为了提高用户接入的安全性&#xff0c;将接入设备Router的接口使能端口安全功能&#xff0c;并且设置接口学习MAC地址数的上限为接入用户数&#xff0c;这样其他外来人员使用自己带来的PC无法访问公…