mysql中Update未加索引導致的微服務模塊不可用
前言
閱讀本文,你可以收獲:
- 線上問題定位和排查思路
- Docker 和 MySQL 相關命令使用
- MySQL 鎖和索引相關知識學習
現(xiàn)象
開發(fā)環(huán)境一個微服務模塊所有接口請求報錯,對應頁面無法訪問。其他未涉及到該模塊的接口和頁面訪問正常。
最近未更新過該服務,之前該服務也沒有發(fā)生過不可用的情況。
錯誤排查
根據(jù)所觀察到的現(xiàn)象,加上簡單思考判斷,可以確定是單個服務出現(xiàn)故障,而且大概率是服務運行一段時間后出現(xiàn)的問題,具體原因尚不清楚。
查看日志
日志是我們排查問題時的第一個入口,根據(jù)日志信息,可以進一步定位問題。
登陸到遠程服務器,執(zhí)行如下命令,查看容器日志。
docker ps // 查看容器 id docker logs -f --tail 2000 容器id // 查看容器最后2000行日志
日志中顯示的報錯信息如下
org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms.
報錯信息顯示連接池請求數(shù)據(jù)庫連接超時,有幾種可能的原因會導致該錯誤:
1、網(wǎng)絡或數(shù)據(jù)庫故障,這也是最先被排除的原因,因為其他微服務運行正常,說明網(wǎng)絡連接沒問題、數(shù)據(jù)庫也沒故障宕機。
2、連接池配置不足,因為業(yè)務請求量并不大,也查看了連接池配置,并無問題,因此這種原因可能性較小,但不排除;
3、連接池最大活躍連接數(shù)達到了上限,連接池的配置無問題,但因為異常原因導致了連接數(shù)達到了上限,這個原因可能性相對來說最高,但還要觀察數(shù)據(jù)庫的運行情況,收集更多信息才能進行下一步判斷。
連接數(shù)據(jù)庫
information_schema 數(shù)據(jù)庫下有幾張表可以幫助我們收集數(shù)據(jù)庫的運行情況。
查看當前數(shù)據(jù)庫運行的所有事務,確認是否有大事務長時間持有數(shù)據(jù)庫連接。表 INNODB_TRX 記錄了當前正在運行的事務信息,包括事務 ID、事務狀態(tài)、事務開始時間、鎖等待時間等。
// 查看當前運行的所有事務 select * from information_schema.INNODB_TRX;
查詢結果如圖。發(fā)現(xiàn)大量事務處于 LOCK WAIT 狀態(tài),只有一個事務處于 RUNNING 狀態(tài),被阻塞的事務都是在執(zhí)行更新同一張表中的記錄操作。

進一步確認,查看當前數(shù)據(jù)庫出現(xiàn)的鎖信息。表 INNODB_LOCKS 記錄了當前被鎖定的對象以及相關的鎖信息,包括事務 ID、鎖類型、鎖定模式、鎖定對象等。注意 MySQL 8.0 版本之后沒有此表。
// 當前出現(xiàn)的鎖 select * from infromation_schema.INNODB_LOCKS; // MySQL 8.0之后執(zhí)行下面語句 select * from performance_schema.data_locks;
查詢結果如圖。鎖的記錄數(shù)正好對應上面查詢的事務數(shù),并且都持有 X 鎖(排他鎖)

問題定位&解決
至此,錯誤產生的原因已經明確:數(shù)據(jù)庫中大量事務占用連接資源并處于阻塞狀態(tài),連接池最大連接數(shù)達到上限,無法獲取新的連接來處理請求。只要找到事務阻塞的原因并且解決,那么問題就解決了。
查看事務執(zhí)行的 SQL 語句和對應的表結構,發(fā)現(xiàn) where 條件后的字段沒有添加索引。更新導致了鎖表?。?!
解決:為字段加上索引(一個索引引發(fā)這么大問題?。?。
alter table 表名 add index 索引名(列名)
問題
為什么服務運行了一段時間后,出現(xiàn)了這個問題?
服務剛運行的時候,連接池資源是夠用的,業(yè)務也能正常使用。但是這條更新語句調用頻繁,會不斷產生新連接執(zhí)行更新操作,然而同一時刻只能有一個事務執(zhí)行(鎖表),其他事務都會阻塞。阻塞的事務越來越多,事務又占有連接資源,可用的連接數(shù)越來越少,服務運行一段時間之后,就出現(xiàn)了問題。
update 沒加索引,為什么會鎖表?
數(shù)據(jù)庫的事務隔離級別是“可重復讀”。在 InnoDB 事務中,對記錄加鎖的基本單位是 next-key 鎖(記錄鎖 + 間隙鎖)。當 update 語句的 where 條件沒有使用索引時,需要掃描整個表來找到滿足 WHERE 條件的記錄,于是就會對所有記錄加上 next-key 鎖,相當于把整個表鎖住了。
update 加上索引,能避免鎖表嗎?
如果條件字段是唯一索引,next-key 鎖會退化成記錄鎖,只會鎖一條記錄,不會鎖表。
如果條件字段不是唯一索引,得看這條語句在執(zhí)行過程中,優(yōu)化器最終選擇的是索引掃描,還是全表掃描,如果走了全表掃描,同樣還是會鎖表。
到此這篇關于mysql中Update未加索引導致的微服務模塊不可用的文章就介紹到這了,更多相關mysql Update未加索引內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
MySQL數(shù)據(jù)表合并去重的簡單實現(xiàn)方法
這篇文章主要給大家介紹了關于MySQL數(shù)據(jù)表合并去重的簡單實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家學習或者使用MySQL具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-05-05

