昨天晚上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、后續可現在預發環境或測試環境先行模擬,評估風險