【作者】

刘博:携程技术保障中心数据库高级经理,主要关注Sql server和Mysql的运维和故障处理。

【环境】

版本号:5.6.21

隔离级别:REPEATABLE READ

【问题描述】

接到监控报警,有一个线上的应用DeadLock报错,每15分钟会准时出现,报错统计如下图:

登录Mysql服务器查看日志:

mysql> show engine innodb status\G
*** (1) TRANSACTION:
TRANSACTION 102973, ACTIVE 11 sec starting index read
mysql tables in use 3, locked 3
LOCK WAIT 4 lock struct(s), heap size 1136, 3 row lock(s)
MySQL thread id 6, OS thread handle 140024996574976, query id 83 localhost us updating
UPDATE TestTable
SET column1 = 1,
Column2 = sysdate(),
Column3= '026’
Column4 = 0
AND column5 = 485
AND column6 = 'SEK'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 417 page no 1493 n bits 1000 index idx_column6 of table test.TestTable trx id 102973 lock_mode X waiting
Record lock, heap no 859 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 3; hex 53454b; asc SEK;;
1: len 8; hex 80000000007e1452; asc ~ R;; *** (2) TRANSACTION:
TRANSACTION 102972, ACTIVE 26 sec starting index read
mysql tables in use 3, locked 3
219 lock struct(s), heap size 24784, 2906 row lock(s), undo log entries 7
MySQL thread id 5, OS thread handle 140024996841216, query id 84 localhost us updating
UPDATE TestTable
SET Column1 = 1,
Column2 = sysdate(),
Column3 = '026'
Column4 = 0
AND Column5 = 485
AND Column6 = 'SEK'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 417 page no 1493 n bits 1000 index idx_Column6 of table test.TestTable trx id 102972 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;; Record lock, heap no 859 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 3; hex 53454b; asc SEK;;
1: len 8; hex 80000000007e1452; asc ~ R;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 601 page no 89642 n bits 1000 index idx_column6 of table test.TestTable trx id 32231892482 lock_mode X locks rec but not gap waiting
Record lock, heap no 38 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 3; hex 53454b; asc SEK;;
1: len 8; hex 80000000007eea14; asc ~ ;;

大致一看,更新同一索引的同一行,应该是一个Block,报TimeOut的错才对,怎么会报DeadLock?

【初步分析】

先分析下(2) TRANSACTION,TRANSACTION 32231892482。

等待的锁信息为:

0: len 3; hex 53454b; asc SEK;;
1: len 8; hex 80000000007eea14; asc

持有的锁信息为:

0: len 3; hex 53454b; asc SEK;;
1: len 8; hex 80000000007eeac4; asc

再先分析下(1) TRANSACTION,TRANSACTION 32231892617。

等待的锁信息为:

0: len 3; hex 53454b; asc SEK;;
1: len 8; hex 80000000007eeac4; asc

于是可以画出的死锁表,两个资源相互依赖,造成死锁:

TRANSACTION Hold Wait
32231892617 53454b\80000000007eea14 53454b\80000000007eeac4
32231892482 53454b\80000000007eeac4 53454b\80000000007eea14

让我们再看一下explain结果:

mysql>desc UPDATE TestTable SET Column1=1, Column2 = sysdate(),Column3 = '025'  Column4 = 0 AND Column5 = 477   AND Column6 = 'SEK' \G;
*************************** 1. row ***************************
id: 1
select_type: UPDATE
table: TestTable
partitions: NULL
type: index_merge
possible_keys: column5_index,idx_column5_column6_Column1,idxColumn6
key: column5_index,idxColumn6
key_len: 8,9
ref: NULL
rows: 7
filtered: 100.00
Extra: Using intersect(column5_index,idxColumn6); Using where

可以看到 EXTRA 列:

Using intersect(column5_index,idxColumn6)

从5.1开始,引入了 index merge 优化技术,对同一个表可以使用多个索引分别进行条件扫描。

相关文档:http://dev.mysql.com/doc/refman/5.7/en/index-merge-optimization.html

The Index Merge method is used to retrieve rows with several range scans and to merge their results into one. The merge can produce unions, intersections, or unions-of-intersections of its underlying scans. This access method merges index scans from a single table; it does not merge scans across multiple tables.

【模拟与验证】

根据以上初步分析,猜测应该就是intersect造成的,于是在测试环境模拟验证,开启2个session模拟死锁:

时间序列 Session1 Session2
1 Begin;
2 UPDATE TestTable SET Column2 = sysdate() Column4 = 0 AND Column5 = 47 AND Column6 = 'SEK
执行成功,影响7行
3 Begin;
4 UPDATE TestTable SET Column2 = sysdate(),Column4 = 0 AND Column5 = 485 AND Column6 = 'SEK';
被Blocking
5 UPDATE TestTable SET Column2 = sysdate(),Column4 = 0 AND Column5 = 485 AND Column6 = 'SEK';
执行成功
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

依据以上信息可以发现Session2虽然被Block了,但也获取了一些Session1在时间序列5时所需资源的X锁,可以再开启一个查询select count(Column5) from TestTable where Column5 = 485,设置SET TRANSACTION ISOLATION LEVEL SERIALIZABLE,去查询Column5 = 485的行,观察锁等待的信息:

mysql> SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query FROM information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id \G;
*************************** 1. row ***************************
waiting_trx_id: 103006
waiting_thread: 36
waiting_query: UPDATE TestTable SET Column1 = 1, Column2 = sysdate(), Column3 = '026' Column4 = 0 AND Column5 = 485 AND Column6 = 'SEK'
blocking_trx_id: 103003
blocking_thread: 37
blocking_query: NULL
*************************** 2. row ***************************
waiting_trx_id: 421500433538672
waiting_thread: 39
waiting_query: select count(Column5) from TestTable where Column5 = 485
blocking_trx_id: 103006
blocking_thread: 36
blocking_query: UPDATE TestTable SET Column1 = 1, Column2 = sysdate(), Column3 = '026' Column4 = 0 AND Column5 = 485 AND Column6 = 'SEK'
2 rows in set, 1 warning (0.00 sec) mysql> select * from information_schema.innodb_lock_waits \G;
*************************** 1. row ***************************
requesting_trx_id: 103006
requested_lock_id: 103006:417:1493:859
blocking_trx_id: 103003
blocking_lock_id: 103003:417:1493:859
*************************** 2. row ***************************
requesting_trx_id: 421500433538672
requested_lock_id: 421500433538672:417:749:2
blocking_trx_id: 103006
blocking_lock_id: 103006:417:749:2
2 rows in set, 1 warning (0.00 sec) mysql> select * from INNODB_LOCKS \G;
*************************** 1. row ***************************
lock_id: 103006:417:1493:859
lock_trx_id: 103006
lock_mode: X
lock_type: RECORD
lock_table: test.TestTable
lock_index: idxColumn6
lock_space: 417
lock_page: 1493
lock_rec: 859
lock_data: 'SEK', 8262738
*************************** 2. row ***************************
lock_id: 103003:417:1493:859
lock_trx_id: 103003
lock_mode: X
lock_type: RECORD
lock_table:test.TestTable
lock_index: idxColumn6
lock_space: 417
lock_page: 1493
lock_rec: 859
lock_data: 'SEK', 8262738
*************************** 3. row ***************************
lock_id: 421500433538672:417:749:2
lock_trx_id: 421500433538672
lock_mode: S
lock_type: RECORD
lock_table: test.TestTable
lock_index: column5_index
lock_space: 417
lock_page: 749
lock_rec: 2
lock_data: 485, 8317620
*************************** 4. row ***************************
lock_id: 103006:417:749:2
lock_trx_id: 103006
lock_mode: X
lock_type: RECORD
lock_table: test.TestTable
lock_index: column5_index
lock_space: 417
lock_page: 749
lock_rec: 2
lock_data: 485, 8317620
4 rows in set, 1 warning (0.00 sec)

可以看到Session2,trx_id 103006阻塞了trx_id 421500433538672,而trx_id 421500433538672 requested_lock也正好是lock_data: 485, 8317620。由此可见Session2虽然别block了,但是还是获取到了Index column5_index相关的锁。被Block是因为intersect的原因,还需要idxColumn6的锁,至此思路已经清晰,对整个分配锁的信息简化一下,如下表格(请求到的锁用青色表示,需获取但未获取到的锁用红色表示):

时间点 Session1 Session2
1 477 SEK
2 485 SEK
3 485 SEK 死锁发生

可以看到485 SEK这两个资源形成了一个环状,最终发生死锁。

【解决方法】

  1. 最佳的方法是添加column5和Column6的联合索引。
  2. 我们环境当时的情况发现Column6的筛选度非常低,就删除了Column6的索引。

    10:55左右删除索引后,报错没有再发生:

MySQL DeadLock故障排查过程的更多相关文章

  1. 一次死锁导致CPU异常飘高的整个故障排查过程

    目录 一.问题详情 top 命令截图 联系腾讯云排查 检查系统日志发现异常 二. 问题解析 三.问题原因 最终结论 四.扩展 进程的几种状态 马后炮 如何快速清理僵尸进程(Z) 内核参数相关 如何查看 ...

  2. 一次ES故障排查过程

    作者:莫那鲁道 原文:http://thinkinjava.cn/#blog 某天晚上,某环境 ES 出现阻塞, 运行缓慢.于是开始排查问题的过程. 开始 思路:现象是阻塞,通常是 CPU 彪高,导致 ...

  3. 企业案例 【故障修复】mysql主从故障解决过程

    由于配置有zabbix监控,某日收到zabbix监控主从报警,,查看mysql状态, showslave status \G; slave复制状态有误,SLAVE_SQL_RUNNING为NO, 接着 ...

  4. 一个杀不死的小强,kill进程无效的原因 记录故障排查过程中kill进程无效的分析过程

    今天在处理一个机器异常负载(1000+)的问题,碰到了一个从未碰到过的情况,遇到了一个异常顽固的分子.我使用了所能想到的所有杀进程的方法,却始终无法干掉这个顽固分子,最后终于在谷歌大神的指引下,干掉了 ...

  5. mysql deadlock found when trying to get lock 问题排查

    mysql deadlock found when trying to get lock 问题排查 1 获 取锁等待情况 可以通过检查 table_locks_waited和table_locks_i ...

  6. 解Bug之路-记一次存储故障的排查过程

    解Bug之路-记一次存储故障的排查过程 高可用真是一丝细节都不得马虎.平时跑的好好的系统,在相应硬件出现故障时就会引发出潜在的Bug.偏偏这些故障在应用层的表现稀奇古怪,很难让人联想到是硬件出了问题, ...

  7. [转] Linux运维常见故障排查和处理的技巧汇总

    作为linux运维,多多少少会碰见这样那样的问题或故障,从中总结经验,查找问题,汇总并分析故障的原因,这是一个Linux运维工程师良好的习惯.每一次技术的突破,都经历着苦闷,伴随着快乐,可我们还是执着 ...

  8. Linux系统运维故障排查

    一.思路 1.处理问题要求 2.一般思路 二.具体问题 1.网络问题 (1)网络不通 (2)网络很慢 2.硬件问题 3.操作系统问题 (1)系统无法正常启动 (2)系统运行慢或死机 4.服务或程序问题 ...

  9. Linux运维常见故障排查和处理的33个技巧汇总

    作为linux运维,多多少少会碰见这样那样的问题或故障,从中总结经验,查找问题,汇总并分析故障的原因,这是一个Linux运维工程师良好的习惯.每一次技术的突破,都经历着苦闷,伴随着快乐,可我们还是执着 ...

随机推荐

  1. composer install 时,提示:Package yiisoft/yii2-codeception is abandoned, you should avoid using it. Use codeception/codeception instead.的解决

    由 SHUIJINGWAN · 2017/11/24 1.composer install 时,提示:Package yiisoft/yii2-codeception is abandoned, yo ...

  2. 2014.1.4 cxf spring webservice

    先创建 webservice 服务端 . 首先下载 cxf jar 包 , cxf-2.7.8 . 新建 web 项目 aa . 将下载的cxf 压缩文件解压,将lib 下的jar 全部build p ...

  3. 在mac console下 执行c++文件

    1 $ g++ -o NewFileName OldFileName.cpp -o is the letter O not zero NewFileName will be your executab ...

  4. DB2 create into的用法

    . 建立表 create table zjt_tables as (select * from tables) definition only; create table zjt_views as ( ...

  5. 着重基础之—Java 8 Comparator: How to Sort a List (List排序)

    着重基础之—Java 8 Comparator: How to Sort a List (List排序) 首先申明,这篇博客的内容不是我自己的知识,我是从国外网站搬来的,原因有二:1是因为大天朝对网络 ...

  6. AngularJS标准Web业务流程开发框架—1.AngularJS模块以及启动分析

    前言: AngularJS中提到模块是自定义的模块标准,提到这不得不说AngularJS是框架中的老大哥,思想相当的前卫..在这框架满天横行的时代,AngularJS有些思想至今未被超越,当然仁者见仁 ...

  7. 《Python3网络爬虫开发实战》PDF+源代码+《精通Python爬虫框架Scrapy》中英文PDF源代码

    下载:https://pan.baidu.com/s/1oejHek3Vmu0ZYvp4w9ZLsw <Python 3网络爬虫开发实战>中文PDF+源代码 下载:https://pan. ...

  8. Python学习-37.Python中的正则表达式

    作为一门现代语言,正则表达式是必不可缺的,在Python中,正则表达式位于re模块. import re 这里不说正则表达式怎样去匹配,例如\d代表数字,^代表开头(也代表非,例如^a-z则不匹配任何 ...

  9. [翻译]NUnit---SetUp and SetUpFixture and Suite Attributes(十九)

    SetUpAttribute (NUnit 2.0 / 2.5) 本特性用于TestFixture提供一个公共的功能集合,在呼叫每个测试方法之前执行.同时也用在SetUpFixture中,SetUpF ...

  10. bootstrap-treeview + angular 使用

    bootstrap-treeview是什么 bootstrap-treeview是一款效果非常酷的基于bootstrap的jQuery多级列表树插件. 怎样使用bootstrap-treeview 插 ...