在 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_size
和 max_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 操作順利進行,需要注意以下幾點:
-
在進行操作前,記得先檢查
innodb_online_alter_log_max_size
值,預估下是否需要修改。可以直接修改爲一個較大值,但是沒有百分百的好事,壞處就是如果業務在 DDL 操作期間併發 DML 修改記錄較多,Online DDL 結束時鎖定表以應用記錄的 DML 時間會增加。所以,選擇好時機很重要,在對的時間做對的事,當然是在業務低峯期,或者考慮工具吧(pt-osc 或 ghost)。
-
在安裝實例時即設置 tmpdir 爲合理的值。
溫馨提示,該值不支持動態修改,真出現問題就晚了,畢竟生產上不允許隨便重啓服務的。
-
及時關注磁盤空間。
不要等到磁盤空間快滿了纔想着通過 Online DDL 操作進行碎片空間清理。例如
optimize table table_name;
,alter table table_name engine=innodb;
等操作。這些操作本身也是需要額外的空間的,等待你的可能是 FAILURE。
更多技術文章,請訪問:https://opensource.actionsky.com/
關於 SQLE
SQLE 是一款全方位的 SQL 質量管理平臺,覆蓋開發至生產環境的 SQL 審覈和管理。支持主流的開源、商業、國產數據庫,爲開發和運維提供流程自動化能力,提升上線效率,提高數據質量。