MySQL相关(九)- 死锁的发生和避免

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: MySQL相关(九)- 死锁的发生和避免


死锁

锁的释放与阻塞

回顾:锁什么时候释放?

事务结束(commit,rollback);客户端连接断开。

如果一个事务一直未释放锁,其他事务会被阻塞多久?会不会永远等待下去?如果是,在并发访问比较高的情况下,如果大量事务因无法立即获得所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖跨数据库。

[Err] 1205 - Lock wait timeout exceeded; try restarting transaction MySQL 有一个参数来控制获取锁的等待时间,默认是 50 秒。

show VARIABLES like 'innodb_lock_wait_timeout';
复制代码

对于死锁,是无论等多久都不能获取到锁的,这种情况,也需要等待 50 秒钟吗?那

不是白白浪费了 50 秒钟的时间吗?

我们先来看一下什么时候会发生死锁。

死锁的发生和检测

死锁演示:

Session 1 Session 2
begin;
select * from t2 where id =1 for update;
- begin;
delete from t2 where id =4 ;
update t2 set name= '4d' where id =4 ;
- delete from t2 where id =1 ;

在第一个事务中,检测到了死锁,马上退出了,第二个事务获得了锁,不需要等待 50 秒:

[Err] 1213 - Deadlock found when trying to get lock; try restarting transaction

为什么可以直接检测到呢?是因为死锁的发生需要满足一定的条件,所以在发生死锁时,InnoDB 一般都能通过算法(wait-for graph)自动检测到。

那么死锁需要满足什么条件?死锁的产生条件:

因为锁本身是互斥的 (1)同一时刻只能有一个事务持有这把锁; (2)其他的事务需要在这个事务释放锁之后才能获取锁,而不可以强行剥夺; (3)当多个事务形成等待环路的时候,即发生死锁。

举例:

理发店有两个总监。一个负责剪头的 Tony 总监,一个负责洗头的 Kelvin 总监。

Tony 不能同时给两个人剪头,这个就叫互斥。

Tony 在给别人在剪头的时候,你不能让他停下来帮你剪头,这个叫不能强行剥夺。如果 Tony 的客户对 Kelvin 总监说:你不帮我洗头我怎么剪头?Kelvin 的客户对 Tony 总监说:你不帮我剪头我怎么洗头?这个就叫形成等待环路。

如果锁一直没有释放,就有可能造成大量阻塞或者发生死锁,造成系统吞吐量下降,这时候就要查看是哪些事务持有了锁。

查看锁信息(日志)

SHOW STATUS 命令中,包括了一些行锁的信息:

show status like 'innodb_row_lock_%';
复制代码

  • Innodb_row_lock_current_waits:当前正在等待锁定的数量;
  • Innodb_row_lock_time :从系统启动到现在锁定的总时间长度,单位 ms;
  • Innodb_row_lock_time_avg :每次等待所花平均时间;
  • Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花的时间;
  • Innodb_row_lock_waits :从系统启动到现在总共等待的次数。

SHOW 命令是一个概要信息。InnoDB 还提供了三张表来分析事务与锁的情况:

select * from information_schema.INNODB_TRX;  -- 当前运行的所有事务 ,还有具体的语句
复制代码

select * from information_schema.INNODB_LOCKS;  --  当前出现的锁
复制代码

select * from information_schema.INNODB_LOCK_WAITS; --  锁等待的对应关系
复制代码

找出持有锁的事务之后呢?

如果一个事务长时间持有锁不释放,可以 kill 事务对应的线程 ID ,也就是 INNODB_TRX 表中的 trx_mysql_thread_id,例如执行 kill 4,kill 7,kill 8。

当然,死锁的问题不能每次都靠 kill 线程来解决,这是治标不治本的行为。我们应该尽量在应用端,也就是在编码的过程中避免。

有哪些可以避免死锁的方法呢?

死锁的避免

  1. 在程序中,操作多张表时,尽量以相同的顺序来访问(避免形成等待环路);
  2. 批量操作单张表数据的时候,先对数据进行排序(避免形成等待环路);
  3. 申请足够级别的锁,如果要操作数据,就申请排它锁;
  4. 尽量使用索引访问数据,避免没有 where 条件的操作,避免锁表;
  5. 如果可以,大事务化成小事务;
  6. 使用等值查询而不是范围查询查询数据,命中记录,避免间隙锁对并发的影响。



相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
5天前
|
关系型数据库 MySQL 中间件
【MySQL实战笔记】07 | 行锁功过:怎么减少行锁对性能的影响?-02 死锁和死锁检测
【4月更文挑战第19天】在高并发环境下,死锁发生在多个线程间循环等待资源时,导致无限期等待。MySQL中,死锁可通过`innodb_lock_wait_timeout`参数设置超时或`innodb_deadlock_detect`开启死锁检测来解决。默认的50s超时可能不适用于在线服务,而频繁检测会消耗大量CPU。应对热点行更新引发的性能问题,可以暂时关闭死锁检测(风险是产生大量超时),控制并发度,或通过分散记录减少锁冲突,例如将数据分拆到多行以降低死锁概率。
19 1
|
2月前
|
SQL 关系型数据库 MySQL
MySQL - 死锁的产生及解决方案
MySQL - 死锁的产生及解决方案
199 0
|
3月前
|
SQL 关系型数据库 MySQL
MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
91 1
|
4月前
|
关系型数据库 MySQL 调度
KnowStreaming系列教程第四篇——MySQL数据更新死锁问题
KnowStreaming系列教程第四篇——MySQL数据更新死锁问题
44 0
|
9月前
|
SQL 监控 算法
MySQL锁定:死锁及其避免方法
MySQL锁定:死锁及其避免方法
|
4月前
|
SQL 存储 关系型数据库
MySQL 意向共享锁、意向排他锁、死锁
MySQL 意向共享锁、意向排他锁、死锁
52 0
MySQL 意向共享锁、意向排他锁、死锁
|
5月前
|
SQL NoSQL 关系型数据库
Mysql Innodb死锁情况分析与归纳
Mysql Innodb死锁情况分析与归纳
54 0
|
11月前
|
SQL 关系型数据库 MySQL
MySQL - 锁等待及死锁初探
MySQL - 锁等待及死锁初探
123 0
|
6月前
|
存储 SQL 关系型数据库
MySQL 优化 index merge(索引合并)引起的死锁分析(强烈推荐)
生产环境出现死锁流水,通过查看死锁日志,看到造成死锁的是两条一样的update语句(只有where条件中的值不同),如下:
|
6月前
|
SQL 关系型数据库 MySQL
Mysql死亡笔记的死锁记录
Mysql死亡笔记的死锁记录
71 0