Mysql新增欄位到大資料表導致鎖表
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> 年初跳完槽,終於可以安心開始寫一些部落格了。進入新的公司,還是有蠻多收穫的。那就先記一個昨天遇到的問題吧。</span>
昨天晚上7點左右,對一張表進行加欄位,大概200多萬條記錄,欄位90多個的大表,結果造成mysql鎖表,進而導致服務不可用。執行語句如下:
ALTER TABLE `sc_stockout_order` ADD `route_remarks` VARCHAR(1024) CHARACTER SET utf8mb4 NULL DEFAULT
mysql配置如下:
開啟服務期日誌,發現有如下報錯:
Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.tomcat.jdbc.pool.PoolExhaustedException: [DubboServerHandler-10.162.99.129:20880-thread-105] Timeout: Pool empty. Unable to fetch a connection in 50 seconds, none available[size:80; busy:79; idle:0; lastwait:50000]. at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:26) ~[mybatis-3.2.8.
我們發現數據庫jdbc拿不到連結,雖然沒有到300最大資料庫連線數,但是兩臺伺服器80*2=160個連結數已經達到配置的客戶端最大連線數。這邊也說明我們客戶端配置的連結數不太合理,可以再稍微調大一點。
發現這個問題後,為了儘快恢復線上服務,用show processlist發現ALTER TABLE這條語句導致大量查詢語句處於等待狀態,趕緊kill 掉修改表格語句的程序,此時系統恢復正常。在這個當中,發現了一條語句如下:
Waiting for table metadata lock
從圖中也可以看到活躍連線數到160之後就不變了,kill掉程序後恢復。
事後查詢資料:
Mysql在5.6版本之前,直接修改表結構的過程中會鎖表,具體的操作步驟如下:
(1)首先建立新的臨時表,表結構通過命令ALTAR TABLE新定義的結構
(2)然後把原表中資料匯入到臨時表
(3)刪除原表
(4)最後把臨時表重新命名為原來的表名
具體ddl如何工作
參考:http://www.cnblogs.com/cchust/p/4639397.html
Mysql 5.6 雖然引入了Online DDL,但是並不是修改表結構的時候,一定不會導致鎖表,在一些場景下還是會鎖表的,比如
①某個慢SQL或者比較大的結果集的SQL在執行,執行ALTER TABLE時將會導致鎖表發生;
②存在一個事務在操作表的時候,執行ALTER TABLE也會導致修改等待;
檢視我們mysql的版本:SELECT VERSION(); 給出:5.6.16-log
我們通過Mysql的慢SQL控制檯,也在發生問題的時間段內沒有出現慢SQL,所以需要排除第一種可能性;
由於當時沒有保留現場,所以當時是不是由於事物導致的鎖表,現在也無從查起,這隻能下次檢視分析了。
根據這次教訓,得到注意項:
1、儘量選擇流量小的事後執行。當天20:00要大促,所以19:00大量供應商在操作。當我們選擇在22:00左右再次執行時,就沒再出現這個問題
2、執行時先看一下有沒有未提交的事務,注意檢視事物information_schema.innodb_trx表
3、隨時關注伺服器日誌狀況,已有問題要先行解決。
4、後續可現在預發環境或測試環境先行模擬,評估風險