MySQL内核月报 2015.03-MySQL · 答疑释惑· 并发Replace into导致的死锁分析

简介:

测试版本:MySQL5.6.23


测试表:

 


背景

Replace into操作可以算是比较常用的操作类型之一,当我们不确定即将插入的记录是否存在唯一性冲突时,可以通过Replace into的方式让MySQL自动处理:当存在冲突时,会把旧记录替换成新的记录。

我们先来理一下一条简单的replace into操作(如上例所示)的主要流程包括哪些。


Step 1. 正常的插入逻辑

首先插入聚集索引记录,在上例中a列为自增列,由于未显式指定自增值,每次Insert前都会生成一个不冲突的新值。

随后插入二级索引b,由于其是唯一索引,在检查duplicate key时,为其加上类型为LOCK_X的记录锁。

Tips:对于普通的INSERT操作,当需要检查duplicate key时,加LOCK_S锁,而对于Replace into 或者 INSERT..ON DUPLICATE操作,则加LOCK_X记录锁。

当UK记录已经存在时,返回错误DB_DUPLICATE_KEY。


Step 2. 处理错误

由于检测到duplicate key,因此第一步插入的聚集索引记录需要被回滚掉(row_undo_ins)。


Step 3. 转换操作

从InnoDB层失败返回到Server层后,收到duplicate key错误,首先检索唯一键冲突的索引,并对冲突的索引记录(及聚集索引记录)加锁。

随后确认转换模式以解决冲突:

  • 如果发生uk冲突的索引是最后一个唯一索引、没有外键引用、且不存在delete trigger时,使用UPDATE ROW的方式来解决冲突;
  • 否则,使用DELETE ROW + INSERT ROW的方式解决冲突。


Step 4. 更新记录

对于聚集索引,由于PK列发生变化,采用delete + insert 聚集索引记录的方式更新。

对于二级uk索引,同样采用标记删除 + 插入的方式。

我们知道,在尝试插入一条记录时,如果插入位置的下一条记录上存在记录锁,那么在插入时,当前session需要对其加插入意向锁,具体类型为LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION。这也是导致死锁的关键点之一。


是否能保证自增列的有序性?

默认情况下,参数innodb_autoinc_lock_mode的值为1,因此只在分配自增列时互斥(如果我们将其设为0的话,就会产生AUTO_INC类型的表级锁)。当分配完自增列值后,我们并不知道并发的replace into的顺序。


死锁分析

回到死锁线程分析,从死锁日志我们大致可以推断出如下序列(本例中死锁的heap no为5):

  • Session 1 执行到Step4, 准备更新二级Uk索引,因此持有uk上heap no 为5的X 行锁和PK上的X行锁;
  • Session 2 检查到uk冲突,需要加X行锁;
  • Session 1 在标记删除记录后,尝试插入新的uk记录,发现预插入点的下一条记录(heap no =5) 上有锁请求,因此尝试加插入意向X锁,产生锁升级, 死锁路径:Session1 => Session 2 => Session1。

到这里其实问题已经很明显了,我们考虑如下场景:假设当前表内数据为:

 

由于不能保证自增列被更新的有序性,我们假定有三个并发的会话,并假定表上只有一条记录。

session 1获得自增列值为2100619, session 2 获得的自增列值为2100614, session 3获得的自增列值为2100616。


Session 1: replace into t1 values (2100619, 2, 3); // uk索引上记录(2, 2100612)被标记删除,同时插入新记录(2, 2100619)

  • Purge线程启动,(2, 2100612)被物理删除,Page上只剩下唯一的物理记录(2, 2100619)。


Session 2: replace into t1 values (2100614, 2, 3);

这里我们使用gdb的non-stop模式,使其断在row_update_for_mysql函数(insert尝试失败后,会转换成update),此时session2持有(2, 2100619) 的X锁。

 


Session 3: replace into t1 values (2100616, 2, 3); // 检测到uk有冲突键,需要获取记录(2, 2100619) 的X锁,等待session 2。


Session 2:

  • a)标记删除记录(2, 2100619),同时插入新记录(2, 2100614);
  • b) (2, 2100614) 比(2, 2100619) 要小,因此定位到该记录之前,也就是系统记录infimum;
  • c)infimum记录的下一条记录(2, 2100619)上有锁等待,需要升级成插入意向X锁,导致死锁发生。


如果Purge线程一直停止,会发生什么呢 ?


我们随便建一个表,然后执行FLUSH TABLE tbname FOR EXPORT来让purge线程停止。

假设当前表上数据为:

 

Session 1:replace into t1 values (2100720, 2, 3);

此时Page上存在记录(infimum), (2, 2100710), (2, 2100720), (supremum)。


Session 2:replace into t1 values (2100715, 2, 3);

同上例,使用gdb断到函数row_update_for_mysql。由于没有启动purge线程,因此老的被标记删除的记录还存在于page内,在扫描二级索引重复键时,也会依次给这些老记录加锁,因此session 2会持有 (2, 2100710)和 (2, 2100720)的X锁。


Session 3:replace into t1 values (2100718, 2, 3); // 被session2阻塞,等待(2,2100710)的X锁


Session 2:在标记删除二级索引记录,并进行插入时,选择的插入位置为 (2, 2100710), (2,2100720)之间,插入点的下一条记录(2,2100720)上没有其他线程锁等待,当前session锁升级成功;

完成插入后,page上的记录分布为(infimum), (2, 2100710), (2, 2100715), (2, 2100720), (supremum)。


Session 3:完成插入,最终page内的记录为(infimum), (2, 2100710), (2, 2100715), (2, 2100718), (2, 2100720), (supremum)。其中只有用户记录(2, 2100718)未被标记删除。


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
存储 关系型数据库 MySQL
MySQL MVCC全面解读:掌握并发控制的核心机制
【10月更文挑战第15天】 在数据库管理系统中,MySQL的InnoDB存储引擎采用了一种称为MVCC(Multi-Version Concurrency Control,多版本并发控制)的技术来处理事务的并发访问。MVCC不仅提高了数据库的并发性能,还保证了事务的隔离性。本文将深入探讨MySQL中的MVCC机制,为你在面试中遇到的相关问题提供全面的解答。
917 2
|
缓存 关系型数据库 MySQL
MySQL并发支撑底层Buffer Pool机制详解
【10月更文挑战第18天】在数据库系统中,磁盘IO操作是性能瓶颈之一。为了提高数据访问速度,减少磁盘IO,MySQL引入了缓存机制。其中,Buffer Pool是InnoDB存储引擎中用于缓存磁盘上的数据页和索引页的内存区域。通过缓存频繁访问的数据和索引,Buffer Pool能够显著提高数据库的读写性能。
574 2
|
SQL 关系型数据库 MySQL
案例剖析:MySQL唯一索引并发插入导致死锁!
案例剖析:MySQL唯一索引并发插入导致死锁!
925 0
案例剖析:MySQL唯一索引并发插入导致死锁!
|
12月前
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
5023 56
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
|
存储 关系型数据库 MySQL
MySQL MVCC深度解析:掌握并发控制的艺术
【10月更文挑战第23天】 在数据库领域,MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种重要的并发控制机制,它允许多个事务并发执行而不产生冲突。MySQL作为广泛使用的数据库系统,其InnoDB存储引擎就采用了MVCC来处理事务。本文将深入探讨MySQL中的MVCC机制,帮助你在面试中自信应对相关问题。
435 3
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
738 1
|
SQL 关系型数据库 MySQL
做MySQL 的并发控制
本文以 MySQL 8.0.35 的代码为例,尝试对 MySQL 中的并发访问控制进行一个整体的介绍。
|
监控 关系型数据库 MySQL
MySQL并发控制与管理
【10月更文挑战第17天】MySQL并发控制与管理
151 0
|
存储 监控 关系型数据库
MySQL并发控制与管理:优化数据库性能的关键
【10月更文挑战第17天】MySQL并发控制与管理:优化数据库性能的关键
1006 0

相关产品

  • 云数据库 RDS MySQL 版
  • 推荐镜像

    更多