記一次Mysql線上死鎖
阿新 • • 發佈:2019-02-19
Mysql死鎖日誌解讀(SHOW ENGINE INNODB STATUS;)
2018-02-01 09:20:25 2b113e040700 INNODB MONITOR OUTPUT ===================================== Per second averages calculated from the last 58 seconds ----------------- BACKGROUND THREAD ----------------- srv_master_thread loops: 11870079 srv_active, 0 srv_shutdown, 7504361 srv_idle srv_master_thread log flush and writes: 19374440 ---------- SEMAPHORES ---------- OS WAIT ARRAY INFO: reservation count 4759173 OS WAIT ARRAY INFO: signal count 58880148 Mutex spin waits 22460199905, rounds 24134283074, OS waits 2319277 RW-shared spins 22518808, rounds 379138472, OS waits 1277864 RW-excl spins 11822536, rounds 295048514, OS waits 1141953 Spin rounds per wait: 24.49 mutex, 16.84 RW-shared, 24.96 RW-excl ------------------------ LATEST DETECTED DEADLOCK ------------------------ 2018-02-01 09:00:12 2b11cc7ce700 *** (1) TRANSACTION: TRANSACTION 1413344039, ACTIVE 1.337 sec starting index read -- 事務ID 1413344039 mysql tables in use 5, locked 5 LOCK WAIT 93 lock struct(s), heap size 13864, 46 row lock(s) LOCK BLOCKING MySQL thread id: 11293490 block 11293500 MySQL thread id 11293500, OS thread handle 0x2b1127380700, query id 2765026522 event_scheduler Sending data --事務1 發生死鎖的語句 update tableB b inner join (select * from tableA b on a.InternalId=b.id)a set ........ *** (1) WAITING FOR THIS LOCK TO BE GRANTED: --等待的鎖資訊 -- space id+ page no + n bits 可以唯一確定一行記錄,等待該記錄的 S鎖(主鍵索引鎖) RECORD LOCKS space id 866455 page no 56 n bits 168 index `PRIMARY` of table `testdb`.`tableA` trx id 1413344039 lock mode S locks rec but not gap waiting Record lock, heap no 85 PHYSICAL RECORD: n_fields 33; compact format; info bits 0 0: len 9; hex 424242445030303031; asc BBBDP0001;; 1: len 6; hex 0000543c9520; asc T< ;; 2: len 7; hex c10005401e359f; asc @ 5 ;; 3: len 4; hex 03fcd08b; asc ;; 4: len 24; hex e794b2e794b3e5aea4e58685e5bbbae7ad91e8aebee8aea1; asc ;; 5: len 4; hex 80000258; asc X;; 6: SQL NULL; 7: len 6; hex e8b4ade789a9; asc ;; 8: SQL NULL; 9: SQL NULL; 10: SQL NULL; 11: len 0; hex ; asc ;; 12: SQL NULL; 13: SQL NULL; 14: len 19; hex 323031352d30382d30352030303a30303a3030; asc 2015-08-05 00:00:00;; 15: SQL NULL; 16: SQL NULL; 17: SQL NULL; 18: len 1; hex 30; asc 0;; 19: SQL NULL; 20: len 19; hex 323031352d30382d30352030363a30393a3033; asc 2015-08-05 06:09:03;; 21: len 19; hex 323031352d30382d30352030363a30393a3033; asc 2015-08-05 06:09:03;; 22: len 4; hex 80000000; asc ;; 23: len 5; hex 474f555755; asc GOUWU;; 24: len 4; hex 80000001; asc ;; 25: len 4; hex 80000000; asc ;; 26: len 4; hex 80000000; asc ;; 27: SQL NULL; 28: SQL NULL; 29: SQL NULL; 30: SQL NULL; 31: SQL NULL; 32: len 4; hex 80000001; asc ;; *** (2) TRANSACTION: TRANSACTION 1413343967, ACTIVE 4.817 sec fetching rows --事務ID 1413343967 mysql tables in use 2, locked 2 116 lock struct(s), heap size 13864, 120 row lock(s) MySQL thread id 11293490, OS thread handle 0x2b11cc7ce700, query id 2765024911 10.29.199.132 bd_db_admin Sending data DELETE from tableA where not EXISTS(select id from tableA_tmp where tableA_tmp.id=tableA.id) and source=4 *** (2) HOLDS THE LOCK(S): --已經持有S鎖 RECORD LOCKS space id 866455 page no 56 n bits 168 index `PRIMARY` of table `testdb`.`tableA` trx id 1413343967 lock_mode X locks rec but not gap --獲取到該記錄行的 X 鎖 Record lock, heap no 85 PHYSICAL RECORD: n_fields 33; compact format; info bits 0 0: len 9; hex 424242445030303031; asc BBBDP0001;; 1: len 6; hex 0000543c9520; asc T< ;; 2: len 7; hex c10005401e359f; asc @ 5 ;; 3: len 4; hex 03fcd08b; asc ;; 4: len 24; hex e794b2e794b3e5aea4e58685e5bbbae7ad91e8aebee8aea1; asc ;; 5: len 4; hex 80000258; asc X;; 6: SQL NULL; 7: len 6; hex e8b4ade789a9; asc ;; 8: SQL NULL; 9: SQL NULL; 10: SQL NULL; 11: len 0; hex ; asc ;; 12: SQL NULL; 13: SQL NULL; 14: len 19; hex 323031352d30382d30352030303a30303a3030; asc 2015-08-05 00:00:00;; 15: SQL NULL; 16: SQL NULL; 17: SQL NULL; 18: len 1; hex 30; asc 0;; 19: SQL NULL; 20: len 19; hex 323031352d30382d30352030363a30393a3033; asc 2015-08-05 06:09:03;; 21: len 19; hex 323031352d30382d30352030363a30393a3033; asc 2015-08-05 06:09:03;; 22: len 4; hex 80000000; asc ;; 23: len 5; hex 474f555755; asc GOUWU;; 24: len 4; hex 80000001; asc ;; 25: len 4; hex 80000000; asc ;; 26: len 4; hex 80000000; asc ;; 27: SQL NULL; 28: SQL NULL; 29: SQL NULL; 30: SQL NULL; 31: SQL NULL; 32: len 4; hex 80000001; asc ;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED: ---等待 space id 866455 page no 257 n bits 168 該記錄的 X 鎖 RECORD LOCKS space id 866455 page no 257 n bits 168 index `PRIMARY` of table `testdb`.`tableA` trx id 1413343967 lock_mode X locks rec but not gap waiting Record lock, heap no 58 PHYSICAL RECORD: n_fields 33; compact format; info bits 0 0: len 4; hex 4a414743; asc JAGC;; 1: len 6; hex 0000543c9520; asc T< ;; 2: len 7; hex c1000540221eb8; asc @" ;; 3: len 4; hex 03fcd483; asc ;; 4: len 12; hex e99d99e5ae89e5b9bfe59cba; asc ;; 5: len 4; hex 8000012c; asc ,;; 6: SQL NULL; 7: len 6; hex e8b4ade789a9; asc ;; 8: SQL NULL; 9: SQL NULL; 10: SQL NULL; 11: len 0; hex ; asc ;; 12: SQL NULL; 13: SQL NULL; 14: len 19; hex 323031352d30382d30352030303a30303a3030; asc 2015-08-05 00:00:00;; 15: SQL NULL; 16: SQL NULL; 17: len 4; hex 37383030; asc 7800;; 18: len 6; hex 333130313030; asc 310100;; 19: SQL NULL; 20: len 19; hex 323031362d30382d30342030383a32313a3338; asc 2016-08-04 08:21:38;; 21: len 19; hex 323031362d30382d30342030383a32313a3338; asc 2016-08-04 08:21:38;; 22: len 4; hex 80000000; asc ;; 23: len 5; hex 474f555755; asc GOUWU;; 24: len 4; hex 80000001; asc ;; 25: len 4; hex 8004baf0; asc ;; 26: len 4; hex 8004bb5a; asc Z;; 27: len 4; hex e220f342; asc B;; 28: len 4; hex e1dcf941; asc A;; 29: SQL NULL; 30: SQL NULL; 31: SQL NULL; 32: len 4; hex 80000001; asc ;; *** WE ROLL BACK TRANSACTION (1) --innodb會根據權重,選擇回滾的事務 ------------ TRANSACTIONS
死鎖原因:
模擬示例
Innodb鎖粒度是行級別的,共享鎖(S)與排他鎖(X)是互斥的,當一方擁有了某行記錄的排他鎖後,另一方就不能其擁有共享鎖,同樣,一方擁有了其共享鎖後,另一方也無法得到其排他鎖。
測試樣例:
上圖中,事務2先申請了一個 id=3 記錄行的 S 鎖, 事務1接著申請一個排他鎖(修改操作會預設加上 X 鎖),此時由於 S X 兩鎖互斥,所以處於等待狀態,若事務2長時間不釋放,事務1會超時退出。
死鎖原因
從Mysql死鎖日誌中看出:事務2已經獲得了X鎖,還要去請求另一條記錄的X鎖。
所以推測出結論:
表一共有10行資料。
因為兩個事務獲取記錄行的順序不一樣,所以在某一時刻:
事務1,已經擁有 前5行資料的 S 鎖,需要獲取後5行記錄的S鎖
事務2,擁有後5行的X 鎖,需要獲取 前5行的X鎖
雙方都在等待需要的鎖,所以發生死鎖。
Select預設為什麼會發送S鎖?
一般的select不會發送 S 鎖,為什麼 線上事故中傳送了S鎖?
模仿線上事故sql:
猜想:在update中有子查詢 select的時候,子查詢select會預設傳送S鎖。
鎖等待的時候,查詢鎖狀態,發現等待的鎖是 S 鎖,即剛才的子查詢select傳送的 鎖。
解決思路:
1.將事務1 中的語句,先select出來,然後在update