線上死鎖問題分析

G8bao7發表於2015-01-08

 轉載自

本文連結地址: 


一個線上死鎖問題分析

死鎖日誌如下:

TRANSACTION 48AA4BB9, ACTIVE 0 sec inserting

mysql tables in use 1, locked 1

LOCK WAIT 6 lock struct(s), heap size 1248, 4 row lock(s), undo log entries 2

MySQL thread id 1409173, OS thread handle 0x5659f940, query id 1084083936 10.246.138.197 bop_libra update

insert into deadlock_test

(deadlock_config_id, block_id, type, gmt_create, gmt_modified)

values

(31643, 92354, 1, now(), now());

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 17 page no 161 n bits 584 index `idx_block_id` of table `deadlock`.`test_deadlock` trx id 48AA4BB9 lock_mode X insert intention waiting

*** (2) TRANSACTION:

TRANSACTION 48AA4BBF, ACTIVE 0 sec inserting, thread declared inside InnoDB 500

mysql tables in use 1, locked 1

5 lock struct(s), heap size 1248, 3 row lock(s), undo log entries 2

MySQL thread id 1393832, OS thread handle 0x7699f940, query id 1084083946 10.246.138.197 bop_libra update

insert into deadlock_test

(deadlock_config_id, block_id, type, gmt_create, gmt_modified)

values

(31643, 92353, 1, now(), now());

*** (2) HOLDS THE LOCK(S):

RECORD LOCKS space id 17 page no 161 n bits 584 index `idx_block_id` of table `deadlock`.`test_deadlock` trx id 48AA4BBF lock_mode X

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 17 page no 161 n bits 584 index `idx_block_id` of table `deadlock`.`test_deadlock` trx id 48AA4BBF lock_mode X insert intention waiting

*** WE ROLL BACK TRANSACTION (2)



表上有聚集索引和二級索引,死鎖發生在二級索引idx_block_id上。

首先,從死鎖資訊:
RECORD LOCKS space id 17 page no 161 n bits 584 index `idx_block_id` of table `deadlock`.`test_deadlock` trx id 48AA4BBF lock_mode X
可以確定,這個x鎖不是由於INSERT產生的。
INSERT可能產生的鎖包括檢查dup key時的s鎖,隱式鎖轉換為顯式鎖(not gap,要在二級索引上產生lock_mode為X的LOCK_ORDINARY型別的鎖(包括記錄及記錄前面的gap),據我所知一般是根據二級索引掃描進行記錄更新導致的。
從5 lock struct(s), heap size 1248, 3 row lock(s), undo log entries 2
有2個undo entires,而單純的INSERT一條記錄只有一個undo entry,因此可以推斷除了INSERT,必然還有別的操作.)
基於以上,事務除了INSERT,可能還存在DELETE/UPDATE,並且這些操作是走的二級索引來查詢更新記錄。
一個簡單但不完全相同的重現步驟:
DROP TABLE t1;
CREATE TABLE `t1` (
  `a` int(11) NOT NULL AUTO_INCREMENT,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  PRIMARY KEY (`a`),
  KEY `b` (`b`)
) ENGINE=InnoDB ;
insert into t1(a, b,c) values(1,2,3),(5,4,6),(8, 7,9),(12,12,19),(15,15,11);

session1:

begin;
delete from t1 where b = 12;
//二級索引上lock_mode X、lock_mode X locks gap before rec以及主鍵上的lock_mode X locks rec but not gap
二級索引:heap_no=5, type_mode=3  (12上的LOCK_ORDINARY型別鎖,包括記錄和記錄前的GAP)
聚集索引:heap_no=5,type_mode=1027
二級索引:heap_no=6,type_mode=547(15上的GAP鎖)
session2:
begin;
delete from t1 where b = 7;
//二級索引上lock_mode X、lock_mode X locks gap before rec以及主鍵上的lock_mode X locks rec but not gap
二級索引:heap_no=4,type_mode=3       (7上的LOCK_ORDINARY型別鎖,包括記錄和記錄前的GAP)
聚集索引:heap_no=4,type_mode=1027
二級索引:heap_no=5,type_mode=547    (記錄12上的GAP鎖)
session1:
insert into t1 values (NULL, 6,10);
//新插入記錄聚集索引無衝突插入成功,二級索引等待插入意向鎖(lock_mode X locks gap before rec insert intention waiting)
二級索引,heap_no=4, type_mode=2819 (請求記錄7上面的插入意向鎖LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION, 需要等待session2
session2:
insert into t1 values (NULL, 7,10);
二級索引:heap_no=5,  type_mode=2819  (請求記錄12上的插入意向鎖LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,需要等待session1)
互相等待,導致發生死鎖
從列印的死鎖資訊來看,基本和線上發生的死鎖現象是一致的。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26250550/viewspace-1395054/,如需轉載,請註明出處,否則將追究法律責任。

相關文章