以MySQL 8.0 來說,通過查看 8.0 的官方文檔得知,8.0 的臨時表空間分為會話臨時表空間和全局臨時表空間,會話臨時表空間存儲用戶創(chuàng)建的臨時表和當 InnoDB 配置為磁盤內(nèi)部臨時表的存儲引擎時由優(yōu)化器創(chuàng)建的內(nèi)部臨時表,當會話斷開連接時,其臨時表空間將被截斷并釋放回池中;也就是說,在 8.0 中有一個專門的會話臨時表空間,當會話被殺掉后,可以回收磁盤空間;而原來的 ibtmp1 是現(xiàn)在的全局臨時表空間,存放的是對用戶創(chuàng)建的臨時表進行更改的回滾段,在 5.7 中 ibtmp1 存放的是用戶創(chuàng)建的臨時表和磁盤內(nèi)部臨時表;
讓客戶滿意是我們工作的目標,不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:域名申請、虛擬主機、營銷軟件、網(wǎng)站建設(shè)、全南網(wǎng)站維護、網(wǎng)站推廣。
也就是在 8.0 和 5.7 中 ibtmp1 的用途發(fā)生了變化,5.7 版本臨時表的數(shù)據(jù)存放在 ibtmp1 中,在 8.0 版本中臨時表的數(shù)據(jù)存放在會話臨時表空間,如果臨時表發(fā)生更改,更改的 undo 數(shù)據(jù)存放在 ibtmp1 中;
實驗驗證:將之前的查詢結(jié)果保存成臨時表,對應(yīng)會話是 45 號,通過查看對應(yīng)字典表,可知 45 號會話使用了 temp_8.ibt 這個表空間,通過把查詢保存成臨時表,可以用到會話臨時表空間,如下圖:
下一步殺掉 45 號會話,發(fā)現(xiàn) temp_8.ibt 空間釋放了,變?yōu)榱顺跏即笮。瑺顟B(tài)為非活動的,證明在 mysql8.0 中可以通過殺掉會話來釋放臨時表空間。
總結(jié):在 mysql5.7 時,殺掉會話,臨時表會釋放,但是僅僅是在 ibtmp 文件里標記一下,空間是不會釋放回操作系統(tǒng)的。如果要釋放空間,需要重啟數(shù)據(jù)庫;在 mysql8.0 中可以通過殺掉會話來釋放臨時表空間。
一、磁盤滿了之后MySQL會做什么?
我們看下官方的說法:
When a disk-full condition occurs, MySQL does the following:
* It checks once every minute to see whether there is enough space to write the current row. If there is enough space,it continues as if nothing had happened.
* Every 10 minutes it writes an entry to the log file, warning about the disk-full condition.
其實MySQL本身并不會做任何操作,如官方文檔說說,只會每分鐘check一次是否有空閑空間,并且10分鐘寫一次錯誤日志。
但是再次期間由于磁盤滿了,意味著binlog無法更新,redo log也無法更新,所有buffer
pool中的數(shù)據(jù)無法被flush上,如果不幸的服務(wù)器重啟,或者實例被kill了,那必然會造成數(shù)據(jù)丟失,這幾乎是一定的。所以,處理磁盤滿的問題最好是先釋放出來一定空間讓dirty數(shù)據(jù)刷新下來。
二、磁盤滿了為什么會導(dǎo)致操作hang住?
1、select
首先經(jīng)過經(jīng)驗和實際測試,select操作不會由于磁盤滿導(dǎo)致問題,也就是所有select操作都會正常運行。
2、insert
經(jīng)過不通的測試發(fā)現(xiàn),當磁盤滿了之后,并不是第一個insert就卡住,而是會在n個之后出現(xiàn)卡住的情況。
通過查看error日志,發(fā)現(xiàn)卡住現(xiàn)象和刷磁盤的操作有關(guān)系。
[ERROR] /usr/local/mysql-5.1.42/libexec/mysqld: Disk is full writing './test/cj_webex.MYD'
[ERROR] /usr/local/mysql-5.1.42/libexec/mysqld: Disk is full writing './mysql-bin.000017'
為了驗證推論是否正確,我們將sync_binlog設(shè)置為1,在這種情況下,insert第一條就卡住了,并且error
log中直接報錯提示寫binlog失敗??磥砜ㄗ〈_實和刷磁盤有關(guān)系。
目前已知和刷磁盤有關(guān)系的參數(shù)有3個,分別是sync_binlog,innodb_flush_log_tr_commit和duoblewrite。
3、show slave status
在從庫經(jīng)過測試,操作會被卡住,這主要是由于執(zhí)行show slave
status需要獲得LOCK_active_mi鎖,然后鎖上mi-data_lock,但是由于磁盤滿了無法將io_thread中的數(shù)據(jù)寫入到relay
log中,導(dǎo)致io_thread持有mi-data_lock鎖,這就導(dǎo)致了死鎖。
所以,這就導(dǎo)致在磁盤滿的情況下,執(zhí)行show slave status操作會卡住。
4、show status
測試可以正常操作,但是如果先執(zhí)行了show slave status操作的情況下,show
status也會被卡住。這是因為執(zhí)行show status需要鎖上LOCK_status,而由于status狀態(tài)中包含slave
status,所以還需要鎖上LOCK_active_mi。如果限制性了show slave
status,這時候由于mi-data_lock死鎖問題,導(dǎo)致io_thread不會釋放LOCK_active_mi鎖。這時候就導(dǎo)致show
status和show slave status爭搶同一把LOCK_active_mi鎖,也形成了死鎖。
所以,在磁盤滿的情況下,如果先執(zhí)行show slave status,后執(zhí)行show status,連個操作都會卡住。
答:MySQL的FLUSH可以清理mysql數(shù)據(jù)庫緩存數(shù)據(jù) MySQL的FLUSH句法(清除或者重新加載內(nèi)部緩存) FLUSH flush_option [,flush_option],如果你想要清除一些MySQL使用內(nèi)部緩存,你應(yīng)該使用FLUSH命令。為了執(zhí)行FLUSH,你必須有reload權(quán)限。 flush_option ...
如果C盤空間本身比較小,只能考慮擴大C盤分區(qū)大小,或者換個硬盤。
如果不是,檢查C盤上新產(chǎn)生,造成磁盤變滿的文件是什么文件,找出原因。
可以通過查看mysql進程來實現(xiàn)。 進入mysql命令行客戶端,選擇數(shù)據(jù)庫后,執(zhí)行show processlist命令: 多刷新幾次,可以看到最后執(zhí)行的SQL語句,以此判斷什么查詢在占用資源。
在對MySQL 8.0.26 vs GreatSQL 8.0.25的對比測試過程中,有一個環(huán)節(jié)是人為制造磁盤滿的場景,看看MGR是否還能正常響應(yīng)請求。
在實測過程中,最后發(fā)現(xiàn)磁盤滿的那個節(jié)點,持續(xù)時間足夠久后,會因為內(nèi)存消耗過大而最終被OS給OOM Kill。
這個問題我已報告BUG(#104979),下面是該過程的詳細記錄。
首先,直接利用dd復(fù)制空文件填滿磁盤。
disk full報告過程及何時被oom killed
來看下MySQL 8.0.26遇到disk full時日志都輸出哪些內(nèi)容:
從disk full時刻開始,大約過了2.5小時,mysqld進程內(nèi)存消耗持續(xù)上升,最終引發(fā)oom kill
在這期間某個時刻抓到的待認證事務(wù)堆積,在被oom kill前實際不止這么多:
關(guān)注mysqld進程內(nèi)存消耗變化
下面是mysqld進程內(nèi)存消耗變化情況
OS層oom-killer相關(guān)日志:
GreatSQL 8.0.25測試過程
作為對比,我用GreatSQL 8.0.25也做了同樣的測試。
從日志詳情中可以看到,當磁盤空間滿了之后,GreatSQL會將那個節(jié)點主動退出集群,對整個集群的影響非常小。
此外,從集群退出后,也不會再接收認證事務(wù)了,所以也沒發(fā)生內(nèi)存持續(xù)暴漲最終被oom killed的情況,實際觀察過程中發(fā)現(xiàn)內(nèi)存反倒還下降了
這樣對比來看,GreatSQL的可靠性還真是可以的,官方的MySQL MGR的可靠性還有待進一步加強呀。
Enjoy GreatSQL :)