由MySQL too many connections引起的事故

問題起因

oj有一個給contest匹配namelist的功能:選擇已經insert的名單,添加到contest的管理界面。

其中有兩個更新名單的按鈕不會自動去重,即 選擇名單後,點擊兩次會插入兩次相同的95人名單,共計190條記錄。

爲了暫時解決這個問題,我直接在MySQL中刪除了後添加的95條數據。

然後通過瀏覽器查看名單,OJ就崩了!!但是如果不看contest相關的功能,oj可以正常work。

重啓apache依舊只能正常訪問非contest模塊。

這個時候我發現MySQL連不上了,顯示Connect failed: Too many connections,修改/etc/my.cnf

max_connections = 1500

重啓MySQL,MySQL可以正常連接了,開頭出現的問題也解決了。

分析原因

1.MySQL最大連接數

MySQL 5.7默認的最大連接數是151 ,文檔在此

既然修改最大連接數解決之前oj卡的問題,大概率是因爲之前MySQL的最大連接數不夠造成的。

2.MySQL隔離級別

既然在修改最大連接數之前,oj除contest相關功能,其他功能都可以正常訪問。

嘗試在本地重現,刪除幾條多餘的記錄,刷新網頁,並沒有卡。

查看本地數據庫,在information_schema數據庫-GLOBAL_VARIABLES表中查看max_connections=151。

說明是訪問非本地數據時纔有的緩存問題,已知MySQL的默認隔離級別是可重複讀,確認當前會話和系統的隔離級別

mysql> use information_schema;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ       |
+-----------------------+
1 row in set, 1 warning (0.00 sec)

均爲可重複讀,即可能出現幻讀錯誤。

3.MySQL鎖

已知oj的MySQL選取InnoDB索引,即默認使用行級鎖。但是當我一下子刪除95條數據的時候,且使用索引操作數據,所以並沒有升級爲表鎖。進而開銷大,加鎖慢;會出現死鎖。

4.web端緩存問題

已知使用Bootstrap前端框架,在加載表格數據時使用的是client模式,即一次性加載全部表格內容,根據設置自動分頁,無需再次請求服務器。

5.在線上重現問題

將最大連接數還原回默認,重啓MySQL,刪除沒用比賽中的某幾條記錄,刷新網頁,oj並沒有卡,懷疑是在線人數較少的原因。

結論

昨晚oj卡的原因是,刪除數據時請求人數過多(當時上公選課 100人左右,都懷疑自己網的問題,一個勁的刷新,導致火上澆油),每個client都持有訪問MySQL的句柄,並且由於當時刪除數據contest相關表格出現死鎖,導致當前連接超過最大連接數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章