最近接了一個(gè)鍋,進(jìn)入新公司接手了一個(gè)進(jìn)入交付階段的項(xiàng)目.在code?review的時(shí)候發(fā)現(xiàn)很多問題,然后開始修復(fù)bug.
在測(cè)試階段突然發(fā)現(xiàn)幾乎所有涉及到更新的操作都失敗,下面貼出異常信息.

第一次出現(xiàn)的時(shí)候百度了一下,猜想可能是多服務(wù)部署資源沖突,重啟服務(wù)故障消失.所以沒有特別重視
第二次出現(xiàn)的時(shí)候只有測(cè)試環(huán)境部署,不存在多機(jī)資源沖突的問題,猜想是多線程資源交叉導(dǎo)致的,于是給可能導(dǎo)致資源競(jìng)爭(zhēng)的地方加上了分布式鎖.
由于無法重現(xiàn)故障,所以并沒有確認(rèn)問題得到解決.
第三次故障依舊,當(dāng)發(fā)現(xiàn)問題依然存在的時(shí)候,開始認(rèn)真反思,發(fā)現(xiàn)自己解決問題的思路明顯有問題,過于片面,一直都只在應(yīng)用層面尋求解決問題的辦法,而且解決問題的方式也只是在嘗試百度出來的方法.并沒有去思考更深層的問題.
知道自己的問題之后開始結(jié)合業(yè)務(wù)在MySQL上尋找解決問題的思路
在Mysql5.5中,information_schema 庫中增加了三個(gè)關(guān)于鎖的表(MEMORY引擎);
INNODB_TRX## 當(dāng)前運(yùn)行的所有事務(wù)
INNODB_LOCKS ## 當(dāng)前出現(xiàn)的鎖
INNODB_LOCK_WAITS ## 鎖等待的對(duì)應(yīng)關(guān)系
通過查詢INNODB_TRX發(fā)現(xiàn)
當(dāng)前事務(wù)中又兩個(gè)RUNNING狀態(tài)開始時(shí)間在一個(gè)小時(shí)之前

開始一直以為是鎖表了
查看了INNODB_LOCKS?事務(wù)信息之后發(fā)現(xiàn)有4行數(shù)據(jù)被鎖住了一直沒有釋放
從這里開始發(fā)現(xiàn)問題了,應(yīng)用已經(jīng)拋了異常,事務(wù)理所當(dāng)然的應(yīng)該回滾才對(duì),為什么資源依然沒有釋放,導(dǎo)致持續(xù)的阻塞呢?
其實(shí)最開始的異常信息就已經(jīng)給出了答案,回到開始的地方,再看異常信息就很清楚了,應(yīng)用里面的異常類是MySQLTransactionRollBackException
是一個(gè)回滾異常,這就說明在事務(wù)回滾的時(shí)候出了問題資源沒有得到釋放
然后開始查詢MySQLTransactionRollBackException?相關(guān)的信息
這個(gè)時(shí)候innodb_rollback_on_timeout=0(默認(rèn)配置)這個(gè)MySQL的配置開始進(jìn)入我的視線,
舉個(gè)栗子
事務(wù)在鎖等待超時(shí)后是回滾事務(wù)內(nèi)所有的statement還是最后一條語句;
?0表示rollback最后一條語句,默認(rèn)值;有點(diǎn)坑爹啊(細(xì)思極恐)
?1表示回滾事務(wù)內(nèi)所有的statements;(此參數(shù)是只讀參數(shù),需在my.cnf中配置,并且重啟生效;)
吃過一次虧,這次并沒有盲目的相信百度到的信息
于是開始測(cè)試
一、驗(yàn)證innodb_rollback_on_timeout=off的情況

1.session?A
? ? 開啟事務(wù),事務(wù)未提交,鎖住id=1的數(shù)據(jù)

2.session B?
開啟事務(wù),執(zhí)行更新id=2的數(shù)據(jù)成功(事務(wù)未提交,鎖住id=2),然后請(qǐng)求id=1等待鎖超時(shí),id=2的數(shù)據(jù)更改為222.

3.session C
請(qǐng)求id=2的數(shù)據(jù)50秒后顯示等待鎖超時(shí)

執(zhí)行SELECT * FROM information_schema.INNODB_TRX;
可發(fā)現(xiàn)有資源一直未釋放,具體到測(cè)試數(shù)據(jù)中就是id=2的資源一直被鎖定,線程一直被掛起.

總結(jié):通過實(shí)驗(yàn)基本可以確定是業(yè)務(wù)資源交叉導(dǎo)致死鎖之后資源沒釋放造成的持續(xù)阻塞,
二.驗(yàn)證innodb_rollback_on_timeout=on
修改配置后將驗(yàn)證innodb_rollback_on_timeout=off的步驟再走一遍
發(fā)現(xiàn)鎖等待只能在業(yè)務(wù)層面盡量避免
on/off的區(qū)別在于session?C進(jìn)入時(shí)不會(huì)持續(xù)阻塞,session B異常后全部回滾