日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql 命令 kill_MySQL之死锁检测

發布時間:2024/7/23 数据库 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 命令 kill_MySQL之死锁检测 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近,筆者在查看線上服務日志時,發現spring大量異常,異常中都顯示了同樣的報錯信息,信息如下。

Deadlock found when trying to get lock; try restarting transaction

調研之后發現是mysql發生了死鎖,這也是筆者第一次遇到數據庫死鎖問題,詳細研究后,將過程記錄為文章,以便日后參考回顧。

1. 死鎖

死鎖指的是兩個或兩個以上的進程(線程)在執行的時候,因為爭奪資源出現相互等待的一種現象。產生死鎖需要同時滿足以下四個條件

  • 互斥條件:一個資源每次只能一個進程使用
  • 不可搶占:進程1在獲取資源,使用的過程中,進程2不能搶占進程1正在使用的資源
  • 占有且等待:進程在申請資源的時,不能釋放已經持有的資源
  • 循環等待:進程1等待進程2資源,同時進程2等待進程1持有的資源,出現循環等待的情況
  • 2. 死鎖日志

    為了查找造成死鎖的sql語句,筆者通過show engine innodb status查看到最近的一次死鎖日志,通過這個sql語句,我們就能確定造成死鎖的事務

    //事務一相關信息 *** (1) TRANSACTION: TRANSACTION 50E, ACTIVE 66 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 3 lock struct(s), heap size 376, 2 row lock(s) MySQL thread id 7, OS thread handle 0x27448, query id 82 localhost 127.0.0.1 root Updating //當前事務正在執行的sql語句 update tb1 set c1= 10 where id =5 //以下信息記錄了鎖等待信息 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: //正在申請主鍵索引行記錄的x鎖 RECORD LOCKS space id 0 page no 3328 n bits 72 index `PRIMARY` of table `test`.`tb1` trx id 50E lock_mode X locks rec but not gap waiting Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 0//事務2相關信息 *** (2) TRANSACTION: TRANSACTION 50F, ACTIVE 47 sec starting index read mysql tables in use 1, locked 1 3 lock struct(s), heap size 376, 2 row lock(s) MySQL thread id 8, OS thread handle 0x277e4, query id 83 localhost 127.0.0.1 root Updating update tb1 set c1= 10 where id =5 //正在持有的鎖:主鍵索引為5的行記錄級別的S鎖 *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 0 page no 3328 n bits 72 index `PRIMARY` of table `test`.`tb1` trx id 50F lock mode S locks rec but not gap Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 00: len 4; hex 80000005; asc ;;1: len 6; hex 00000000050d; asc ;;2: len 7; hex 8b00000d080110; asc ;;3: len 4; hex 80000005; asc ;;4: len 4; hex 80000005; asc ;;*** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 0 page no 3328 n bits 72 index `PRIMARY` of table `test`.`tb1` trx id 50F lock_mode X locks rec but not gap waiting Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 00: len 4; hex 80000005; asc ;;1: len 6; hex 00000000050d; asc ;;2: len 7; hex 8b00000d080110; asc ;;3: len 4; hex 80000005; asc ;;4: len 4; hex 80000005; asc ;;WE ROLL BACK TRANSACTION (2)

    筆者發現死鎖日志最后一行出現了WE ROLL BACK TRANSACTION (2)信息。這是Mysql innodb引擎自動檢測死鎖機制,MySQL選擇打斷其中一個事務破壞死鎖條件來消除死鎖。Mysql官方文檔上顯示,mysql會選擇殺死小的事務,這里的小指的是執行的insert,update,detected語句數目小的事務。需要注意的是mysql innodb死鎖檢測只能針對innodb引擎級別死鎖,innodb死鎖檢測不能檢測到應用層級別死鎖

    3. 死鎖復現

    為了避免泄露公司的業務和數據,筆者在開發環境復現了這個死鎖

    表結構如下所示

    事務執行順序如下

    為什么這個sql語句會造成死鎖呢?原因如下

    4. 解決方案

    通過上文的死鎖復現,筆者發現事務2和事務3的作用一樣的,他們都操作了相同的資源,執行事務2和事務3可能是同一進程內的線程執行,也可能是位于不同進程的線程執行。針對這種情況,筆者在生產環境使用分布式鎖解決這種死鎖場景,筆者以操作的行記錄id作為分布式資源id,關于分布式鎖,可以參考筆者先前寫的文章

    5. 發現死鎖

    上述場景,Mysql發現了死鎖,并選擇回滾其中一個事務解決了死鎖問題,但是老版本的mysql沒有死鎖檢測機制,如果出現死鎖,連接可能都會處于等待狀態,直到50S的鎖等待超時,這會長時間占據數據庫連接,導致數據庫連接池連接耗盡,tomcat無法獲取數據庫連接,一直處于等待狀態,隨后tomcat隊列排滿后,整個服務就會處于僵死狀態,在生產環境中是非常大的事故。如果發現mysql執行SQL語句長時間不響應。我們可以通過show full processlist 命令查看當前所有數據庫連接狀態,如果連接在等待鎖資源,在State狀態會顯示waiting for table metadata lock信息,同時可以通過info信息查看數據庫連接執行了哪一條sql語句,如果所有的等待鎖的連接執行的sql語句都涉及到了同一張表,那么就能斷定哪站表發生了死鎖

    6. 查找連接

    知道哪張表被鎖定仍然無法解決我們的問題,我們需要知道哪個數據庫連接對表加了鎖,才能kill連接,從mysql5.5開始,information_schema增加了三個關于鎖的表,通過這三張表,我們能夠找到連接id

    6.1 innodb_locks

    這張表提供了各個事務請求的數據庫鎖但是仍然沒有獲取的數據庫鎖。這張表提供的最重要的信息是請求鎖的事務id

    6.2 innodb_trx

    通過這張表我們能查到當前innodb引擎執行的所有事務id以及當前執行事務的數據庫連接id,于是便能通過kill命令殺死數據庫連接,更關鍵的是我們能查找到事務正在執行的sql語句

    6.3 innodb_lock_waits

    這張表中requesting_trx_id代表了申請鎖資源的事務ID,requesting_lock_id代表申請的鎖id,blocking_trx_id代表了阻塞事務70E的事務id,blocking_lock_id代表了阻塞事務70E的鎖的ID

    出現死鎖后,我們可以通過innodb_lock_waits獲取相互等待的事務id,通過事務id從innodb_trx查找到數據庫連接id,然后使用kill殺死連接

    7. 應用層死鎖

    innodb_locks,innodb_trx,innodb_lock_waits三張表只能查找到innodb引擎層死鎖的數據庫連接id,對于server層死鎖就無能為力了。比如說下述命令加的鎖

    lock tables tb1 write; flush tables with read lock;

    針對這種死鎖,無法通過殺死數據庫連接id達到釋放鎖的目的,針對這種情況筆者尚未找到解決方案,在生產環境下,筆者也遇到過這種情況造成的死鎖,筆者只能尋求DBA重啟數據庫可以暫時解決死鎖問題,但是最好的解決方案是盡量不要使用手動加鎖命令。

    總結

    以上是生活随笔為你收集整理的mysql 命令 kill_MySQL之死锁检测的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。