如何避免Mysql RR 隔离级别下的 INSERT 死锁

embedded/2024/10/21 11:45:11/

背景

        我们公司架构师,在使用 Mysql 做分布式锁的时候,因 insert 唯一键冲突,造成死锁。引起我对这部分知识点的兴趣和研究。

        死锁日志的详细信息如下:

LATEST DETECTED DEADLOCK
------------------------
2024-08-19 16:32:45 0x7f92b0ca2700
*** (1) TRANSACTION:
TRANSACTION 329612456, ACTIVE 3 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 3365552, OS thread handle 140263881365248, query id 1432399623 192.168.18.207 root update
-- step6:插入 ConsumeLogAlarmLock
insert into t_distributed_lock (lock_key) values ('ConsumeLogAlarmLock')
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 10113 page no 4 n bits 72 index uk_lock_key of table `shouba_gy`.`t_distributed_lock` trx id 329612456 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 00: len 8; hex 73757072656d756d; asc supremum;;*** (2) TRANSACTION:
TRANSACTION 329612441, ACTIVE 7 sec inserting
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 1
MySQL thread id 3365470, OS thread handle 140268007991040, query id 1432399406 192.168.18.207 root update
-- step4:插入 ConsumeLogAlarmLock
insert into t_distributed_lock (lock_key) values ('ConsumeLogAlarmLock')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 10113 page no 4 n bits 72 index uk_lock_key of table `shouba_gy`.`t_distributed_lock` trx id 329612441 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 00: len 8; hex 73757072656d756d; asc supremum;;*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 10113 page no 4 n bits 72 index uk_lock_key of table `shouba_gy`.`t_distributed_lock` trx id 329612441 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 00: len 8; hex 73757072656d756d; asc supremum;;*** WE ROLL BACK TRANSACTION (2)

前置知识

  • insert 会对插入的这条记录加排他记录锁,在 insert 记录锁之前还会加一种 GAP 锁,叫做插入意向锁,如果出现唯一键冲突,还会加一个共享记录锁(S Next-Key Lock)。具体可以去
    MySQL 官方文档 查看
  • Mysql 5.7 和Mysql 8.0 涉及事务和锁的3 个基表

       Mysql 5.7

                information_schema.innodb_locks

                information_schema.innodb_lock_waits  -- 查看当前等待的锁

                information_schema.innodb_trx -- 查询当前的事务信息

        Mysql 8.0

                performance_schema.data_locks

                performance_schema.data_lock_waits  -- 查看当前等待的锁

                information_schema.INNODB_TRX -- 查询当前的事务信息

        MySQL 5.7 中,information_schema.innodb_locks 包含这些数据:

                InnoDB 事务已申请但未获得的锁。

                InnoDB 事务已持有并且阻塞了其它事务的锁。

        MySQL 8.0 中,performance_schema.data_locks 包含这些数据:

                InnoDB 事务已申请但未获得的锁。

                InnoDB 事务正在持有的锁。

锁的兼容矩阵

`GapInsert IntentionRecordNext-Key
Gap兼容兼容兼容兼容
Insert Intention冲突兼容兼容冲突
Record兼容兼容冲突冲突
Next-Key兼容兼容冲突冲突

注:横向是已经持有的锁,纵向是正在请求的锁

typeISIXSX
IS兼容兼容兼容不兼容
IX兼容兼容不兼容不兼容
S兼容不兼容兼容不兼容
X不兼容不兼容不兼容不兼容

              

前置准备

Mysql 版本: 5.7.17

隔离级别为:REPEATABLE-READ

表结构:

java">-- 建表
CREATE TABLE `t_distributed_lock` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`lock_key` varchar(255) NOT NULL COMMENT '锁名称',PRIMARY KEY (`id`),UNIQUE KEY `uk_lock_key` (`lock_key`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;-- 插入数据
insert into t_distributed_lock2 (lock_key) values ('ConsumeLogAlarmLock');

Sql 语句执行流程:

时刻

Session 1

Session 2

Session 3

T1

begin;

delete from t_distributed_lock2 where lock_key = 'ConsumeLogAlarmLock';

T2

begin;

insert into t_distributed_lock2 (lock_key) values ('ConsumeLogAlarmLock');

T3

begin;

insert into t_distributed_lock2 (lock_key) values ('ConsumeLogAlarmLock');

T4

COMMIT;

DEADLOCK,ROLLBACK;

 原因分析

T1 时刻    

session1 插入记录成功,此时对应的索引记录被隐式锁保护,未生成锁结构。

T2 时刻

session2 插入记录检测到插入值和 session1 唯一键冲突。

  • session2 帮助 session1 对 lock_key = ConsumeLogAlarmLock 的记录产生了一个显式的锁结构。

  • session2 自身产生 S 型的 NEXT-KEY LOCK,请求范围为 (-∞,ConsumeLogAlarmLock ],但是其只能获取到 (-∞,ConsumeLogAlarmLock ) 的 GAP LOCK,而被 session1 的 lock_key = ConsumeLogAlarmLock 的记录锁阻塞。

T3 时刻

session3 插入记录检测到插入值和 session1 唯一键冲突。

  • session3 自身产生 S 型的 NEXT-KEY LOCK,请求范围为 (-∞,ConsumeLogAlarmLock ],但是其只能获取到 (-∞,ConsumeLogAlarmLock ) 的 GAP LOCK,而被 session1 的 lock_key = ConsumeLogAlarmLock 的记录锁阻塞。

T4 时刻

  • session1 执行 COMMIT,释放X锁。session2 和 session3 都获得 S Next-Key Lock;
  • session2 和 session3 继续执行插入操作,这个时候 INSERT INTENTION LOCK(插入意向锁)出现了,并且由于插入意向锁会被 gap 锁阻塞,所以 session2 和 session3 互相等待,造成死锁。

至此,形成闭环锁等待,死锁条件达成:session2 和 session3 分别想要在插入的间隙 (-∞,ConsumeLogAlarmLock) 获得插入意向锁,但分别被对方持有的 GAP 锁阻塞。

参考文章

技术分享 | 如何避免 RC 隔离级别下的 INSERT 死锁 - 墨天轮

MySQL :: MySQL 8.0 Reference Manual :: 17.7.3 Locks Set by Different SQL Statements in InnoDB

解决死锁之路 - 常见 SQL 语句的加锁分析 - aneasystone's blog


http://www.ppmy.cn/embedded/97508.html

相关文章

iPhone很多空相簿怎么删除:简化你的照片库

随着我们使用iPhone拍摄越来越多的照片和视频,管理这些内容的需求也随之增加。创建相簿是组织照片的一种便捷方式,但随着时间的推移,可能会产生许多未使用或空的相簿。这些空相簿不仅占用了照片应用的界面空间,也让照片库显得更加…

转行网络安全,应该选哪个方向?(非常详细)零基础入门到精通,收藏这一篇就够了

随着互联网技术的快速发展和广泛应用,网络安全形势日益严峻,各种网络攻击和安全威胁不断涌现,给个人、企业乃至国家带来了巨大的风险。为了应对网络风险,网络安全越来越被重视,开始成为入行互联网的备选岗位。 网络安…

第八周:机器学习笔记

第八周机器学习笔记 摘要Abstract机器学习1. 鱼和熊掌和可兼得的机器学习1.1 Deep network v.s. Fat network 2. 为什么用来验证集结果还是不好? Pytorch学习1. 卷积层代码实战2. 最大池化层代码实战3. 非线性激活层代码实战 总结 摘要 本周学习对李宏毅机器学习视…

uniapp left right 的左右模态框

标题 这是组件 <template><div class"content-wrapper"><divv-for"(vla, i) in products":key"i":class"[content-page, getPageClass(i)]"><slot :data"vla"><!-- 用户自定义的内容 --><…

基于Spring boot的名城小区物业管理系统

TOC springboot240基于Spring boot的名城小区物业管理系统 绪论 1.1研究背景与意义 1.1.1研究背景 近年来&#xff0c;第三产业发展非常迅速&#xff0c;诸如计算机服务、旅游、娱乐、体育等服务行业&#xff0c;对整个社会的经济建设起到了极大地促进作用&#xff0c;这一…

【保姆级】独家揭秘!体验Sora模型的官方途径 —— OpenAI Red Teaming Network

前言 OpenAI推出的Sora模型在AI界掀起了一股热潮&#xff0c;不仅让业内人士激动不已&#xff0c;也让外界对通用人工智能&#xff08;AGI&#xff09;产生了浓厚的兴趣。 Sora的火爆程度&#xff0c;引得许多人好奇&#xff1a;我们何时才能体验Sora的魅力&#xff1f; 在O…

图片文件比较大怎么办?分享4个简单的在线压缩图片工具

现在经常将图片发布到网上用来展示&#xff0c;但是随着图片质量越高相应的文件也比较大&#xff0c;在遇到图片文件较大问题时&#xff0c;经常会无法正常上传到网站使用&#xff0c;所以一般需要使用图片压缩功能来调整大小后使用。对于经常需要处理图片的小伙伴来说&#xf…

解析网络流量管理方案:简化基于云的DNS负载均衡

数字化时代&#xff0c;网络规模和流量需求的增长&#xff0c;催生了用户对可用性的需求、管理员对更好的访问和管理等需求。在大型的网络应用中&#xff0c;为保障站点的稳定性&#xff0c;会为服务或站点提供多台服务器&#xff0c;以平均分配每台服务器上的压力&#xff0c;…