大多數用戶在對於磁碟進行分區的時候都是習慣性的不給系統盤預留很大空間,其實這並不是一個好習慣。因為系統分區並不像我們想象的那樣會僅僅安裝一個操作系統,系統分區多數還是會承載操作系統主要應用軟體安裝任務。那麼當磁碟空間爆滿後,MySQL會發生什麼事呢?又應該怎麼應對? 會發生什麼事 當磁碟空間寫滿了之 ...
大多數用戶在對於磁碟進行分區的時候都是習慣性的不給系統盤預留很大空間,其實這並不是一個好習慣。因為系統分區並不像我們想象的那樣會僅僅安裝一個操作系統,系統分區多數還是會承載操作系統主要應用軟體安裝任務。那麼當磁碟空間爆滿後,MySQL會發生什麼事呢?又應該怎麼應對?
會發生什麼事
當磁碟空間寫滿了之後,MySQL是無法再寫入任何數據的,包括對錶數據的寫入,以及binlog、binlog-index等文件。
當然了,因為InnoDB是可以把臟數據先放在記憶體里,所以不會立刻表現出來無法寫入,除非開啟了binlog,寫入請求才會被阻塞。
當MySQL檢測到磁碟空間滿了,它會怎麼樣呢?下麵我們來看一個具體例子:
磁碟滿了之後MySQL會做什麼?
我們看下官方的說法
其實MySQL本身並不會做任何操作,如官方文檔說說,只會每分鐘check一次是否有空閑空間,並且10分鐘寫一次錯誤日誌。
但是再次期間由於磁碟滿了,意味著binlog無法更新,redolog也無法更新,所有bufferpool中的數據無法被flush上,如果不幸的伺服器重啟,或者實例被kill了,那必然會造成數據丟失,這幾乎是一定的。所以,處理磁碟滿的問題最好是先釋放出來一定空間讓dirty數據刷新下來。
磁碟滿了為什麼會導致操作hang住?
1、select
首先經過經驗和實際測試,select操作不會由於磁碟滿導致問題,也就是所有select操作都會正常運行。
2、insert
經過不通的測試發現,當磁碟滿了之後,並不是第一個insert就卡住,而是會在n個之後出現卡住的情況。
通過查看error日誌,發現卡住現象和刷磁碟的操作有關係。
為了驗證推論是否正確,我們將sync_binlog設置為1,在這種情況下,insert第一條就卡住了,並且errorlog中直接報錯提示寫binlog失敗。看來卡住確實和刷磁碟有關係。
目前已知和刷磁碟有關係的參數有3個,分別是sync_binlog,innodb_flush_log_tr_commit,和duoblewrite。
3、showslavestatus
在從庫經過測試,操作會被卡住,這主要是由於執行showslavestatus需要獲得LOCK_active_mi鎖,然後鎖上mi->data_lock,但是由於磁碟滿了無法將io_thread中的數據寫入到relaylog中,導致io_thread持有mi->data_lock鎖,這就導致了死鎖。
所以,這就導致在磁碟滿的情況下,執行showslavestatus操作會卡住。
4、showstatus
測試可以正常操作,但是如果先執行了showslavestatus操作的情況下,showstatus也會被卡住。這是因為執行showstatus需要鎖上LOCK_status,而由於status狀態中包含slavestatus,所以還需要鎖上LOCK_active_mi。如果限制性了showslavestatus,這時候由於mi->data_lock死鎖問題,導致io_thread不會釋放LOCK_active_mi鎖。這時候就導致showstatus和showslavestatus爭搶同一把LOCK_active_mi鎖,也形成了死鎖。
所以,在磁碟滿的情況下,如果先執行showslavestatus,後執行showstatus,連個操作都會卡住。
應該怎麼辦
那麼,當發現磁碟空間滿了之後,我們應該怎麼處理呢,建議:
每分鐘:檢查空間是否得到釋放,以便寫入新數據。當發現有剩餘空間了,就會繼續寫入數據,一切照舊。
每十分鐘:如果還是發現沒剩餘空間,則會在日誌中寫入一條記錄,報告磁碟空間滿(這時候只寫入幾個位元組還是夠的)。
提高監控系統檢測頻率,預防再次發生;
及時刪除不用的文件,釋放空間;
若有線程因磁碟滿的問題被阻塞了,可先殺掉,等到下一分鐘重新檢測時它可能又可以正常工作了;
可能因磁碟滿導致某些線程被阻塞,引發其他線程也被阻塞,可把導致阻塞的線程殺掉,其他被阻塞的線程也就能繼續工作了。
例外
有個例外的情況是:
當執行REPAIRTABLE或者OPTIMIZETABLE操作時,或者執行完LOADDATAINFILE或ALTERTABLE之後批量更新索引時,這些操作會創建臨時文件,當執行這些操作過程中mysqld發現磁碟空間滿了,就會把這個涉及到的表標記為crashed,刪掉臨時文件(除了ALTERTABLE操作,MySQL會放棄正在執行的操作,刪除臨時文件,釋放磁碟空間)。
備註:當執行這些命令過程中mysqld進程被意外被殺掉的話,其所生成臨時文件不會自動刪除,需要手工刪掉才能釋放磁碟空間。