前兩天遇到一個1205(ER_LOCK_WAIT_TIMEOUT)的錯誤,弄了半天終於找到原因,掌握原理+細心才能找到罪歸禍首。下面我給大家分享下這個問題的分析處理過程,希望對大家有所幫助。接到slave error告警后,看到現場是這樣的:slave重做binlog因為鎖超時中斷,報HA_ERR_LOCK_WAIT_TIMEOUT錯誤。
超時,easy啊,心想估計是有大事務長期持有鎖,導致其他事務超時等待。但是這個庫是只讀的備庫,不可能有寫事務,通過show processlist命令也確實沒有發現寫事務,倒是有一個大查詢任務。當時覺得MVCC查詢不上鎖啊,直接無視。我嘗試重新start slave,發現沒過幾秒鍾,錯誤依然出現,並且Exec_Master_Log_Pos沒有變化,這說明同樣的事務嘗試寫錯誤,依然被堵住,導致鎖超時等待了。這一定是事務持有鎖導致鎖超時,但機器上除了查詢,啥也木有。隔離級別,確認下隔離級別,雖然生產環境中機器都是RC(讀提交)模式,但也不排除這種可能。但結果再次讓我失望,事務隔離級別是讀提交。
會不會是存儲引擎的問題,我又驗證了一把,表是innodb存儲引擎,讀不存在說是上表鎖的情況。無語了,難道innodb的MVCC,讀在某些情況下也上鎖?這豈不是與讀不上鎖上違背嗎?繼續排查問題,查看鎖等待情況:
select * from information_schema.innodb_lock_waits;
這說明確實有事務堵住了更新。繼續,
SELECT r.trx_id waiting_trx_id,
r.trx_query waiting_query,
b.trx_id blocking_trx_id,
b.trx_query blocking_query,
b.trx_mysql_thread_id blocking_thread,
b.trx_started,
b.trx_wait_started
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
從圖中可以看到,blocking_query確實是select語句,靠,難道真是它上鎖了,上的什么鎖呢?
select * from information_schema.innodb_locks;
可以看到一個讀鎖和一個寫鎖,這說明了,查詢的確是上了記錄的讀鎖,鎖應該都是在innodb層面加的。到底為啥會上讀鎖呢?
select trx_id,trx_state,trx_isolation_level from information_schema.innodb_trx;
答案揭曉了,可以看到RUNNING的事務隔離級別是SERIALIZABLE,串行化隔離級別導致讀上鎖,進而阻塞復制無法進行下去。
這個例子其實很簡單,通過這個例子可以看到,information_schema下面的幾張表太重要了,暴露了很多信息,方便我們排查問題。同時排查問題時,一定要堅信原理,並且細心,問題總會水落石出。