MySQL 執行 Online DDL 操作報錯空間不足?

在 MySQL 中執行 Online DDL 之前,需要保證在三個方面的空間充足。

作者:徐文梁,愛可生 DBA 成員,一個執着於技術的數據庫工程師,主要負責數據庫日常運維工作。擅長 MySQL,Redis 及其他常見數據庫也有涉獵;喜歡垂釣,看書,看風景,結交新朋友。

愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。

本文約 1400 字,預計閱讀需要 4 分鐘。

問題背景

客戶反饋對某張表執行 alter table table_name engine=innodb; 時報錯空間不足。

通過登錄數據庫查看客戶的 tmpdir 設置的路徑,發現是 /tmp。該目錄磁盤空間本身較小,調整 tmpdir 的路徑與數據目錄相同,重新執行 ALTER 操作執行成功。

問題到此結束了,但是故事並沒有結束。通過查看官網信息,我們可以從這個小小的報錯中深挖更多信息。

信息解讀

從官網的論述中,我們可以瞭解到,在進行 Online DDL 操作時,需要保證以下三個方面的空間充足,否則可能會導致空間不足報錯。

臨時日誌文件

當進行 Online DDL 操作創建索引或者更改表時,臨時日誌文件會記錄期間的併發 DML 操作,臨時日誌文件最大值由 innodb_online_alter_log_max_size 參數控制,如果 Online DDL 操作耗時較長(如果表數據量較大這是很有可能的),並且期間併發 DML 對錶中的記錄修改較多,則可能導致臨時日誌文件大小超過 innodb_online_alter_log_max_size 值,從而引發 DB_ONLINE_LOG_TOO_BIG 錯誤,並回滾未提交的併發 DML 操作。

臨時排序文件

對於會重建表的 Online DDL 操作,在創建索引期間,會將臨時排序文件寫入到 MySQL 的臨時目錄。僅考慮 UNIX 系統,對應的參數爲 tmpdir,如果 /tmp 目錄比較小,請設置該參數爲其他目錄,否則可能會因爲無法容納排序文件而導致 Online DDL 失敗。

中間表文件

對於會重建表的 Online DDL 操作,會在與原始表相同的目錄中創建一個臨時中間表文件,中間表文件可能需要與原始表大小相等的空間。中間表文件名以 #sql-ib 前綴開頭,僅在 Online DDL 操作期間短暫出現。

前置準備

針對官網的論述,我們可以進行實際測試,這裏對臨時排序文件和中間表文件場景進行測試,爲了故事更好的發展,先做一些準備工作:

1. 創建一個測試庫

數據目錄對應爲 /opt/mysql/data/3310/my_test

create database my_test;

2. 限制數據目錄大小

#創建一個指定大小的磁盤鏡像文件,這裏爲 600M
dd if=/dev/zero of=/root/test.img bs=60M count=10

#掛載設備
losetup /dev/loop0 /root/test.img

#格式化設備
mkfs.ext3 /dev/loop0

#掛載爲文件夾,則限制其文件夾空間大小爲 600M
mount -t ext3 /dev/loop0 /opt/mysql/data/3310/my_test

#修改屬組爲 MySQL 服務對應用戶
chown -R mysql.mysql /opt/mysql/data/3310/my_test

3. 創建一張測試表

CREATE TABLE `student` (
`id` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`score` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`sex` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

4. 插入一些數據

注意:數據量不要太小,小於 /opt/mysql/data/3310/my_test 目錄的一半,建議 30% 左右。

./mysql_random_data_load -h127.0.0.1 -P3310 -uuniverse_op -p'xxx' --max-threads=8 my_test student 1500000

5. 修改 /tmp 大小

這裏 tmpdir 目錄爲 /tmp,修改 /tmp 大小爲一個較小值。

mount -o remount,size=1M tmpfs /tmp

6. 修改其他參數

修改 tmp_table_sizemax_heap_table_size 值爲較小值,這裏僅僅爲了便於生成磁盤臨時文件,生產環境不建議,會嚴重影響性能。

set sort_buffer_size=128*1024;
set tmp_table_size=128*1024;

場景測試

登錄數據庫執行如下操作,可以觀察到添加索引失敗,報錯信息如下:

mysql> alter table student add  idx_name index(name);
ERROR 1878 (HY000): Temporary file write failure.

執行如下操作修改 /tmp 目錄大小,再次執行 ALTER 操作成功。

[root@localhost ~]# mount -o remount,size=500M tmpfs /tmp
mysql> alter table student add index(name);
Query OK, 0 rows affected (4.92 sec)
Records: 0 Duplicates: 0 Warnings: 0

觀察 /opt/mysql/data/3310/my_test 目錄已使用空間,如果使用率較低,建議繼續插入數據到磁盤空間使用率超過 50%

執行如下操作,會報如下錯誤:

mysql> alter table student engine=innodb;
ERROR 1114 (HY000): The table 'student' is full

問題總結

好了,最後總結一下。爲了我們的 Online DDL 操作順利進行,需要注意以下幾點:

  1. 在進行操作前,記得先檢查 innodb_online_alter_log_max_size 值,預估下是否需要修改。

    可以直接修改爲一個較大值,但是沒有百分百的好事,壞處就是如果業務在 DDL 操作期間併發 DML 修改記錄較多,Online DDL 結束時鎖定表以應用記錄的 DML 時間會增加。所以,選擇好時機很重要,在對的時間做對的事,當然是在業務低峯期,或者考慮工具吧(pt-oscghost)。

  2. 在安裝實例時即設置 tmpdir 爲合理的值。

    溫馨提示,該值不支持動態修改,真出現問題就晚了,畢竟生產上不允許隨便重啓服務的。

  3. 及時關注磁盤空間。

    不要等到磁盤空間快滿了纔想着通過 Online DDL 操作進行碎片空間清理。例如 optimize table table_name;alter table table_name engine=innodb; 等操作。這些操作本身也是需要額外的空間的,等待你的可能是 FAILURE。

更多技術文章,請訪問:https://opensource.actionsky.com/

關於 SQLE

SQLE 是一款全方位的 SQL 質量管理平臺,覆蓋開發至生產環境的 SQL 審覈和管理。支持主流的開源、商業、國產數據庫,爲開發和運維提供流程自動化能力,提升上線效率,提高數據質量。

SQLE 獲取

類型 地址
版本庫 https://github.com/actiontech/sqle
文檔 https://actiontech.github.io/sqle-docs/
發佈信息 https://github.com/actiontech/sqle/releases
數據審覈插件開發文檔 https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章