趨近完美的 Undo 空間

資深數據庫專家,專研 MySQL 十餘年。擅長 MySQL、PostgreSQL、MongoDB 等開源數據庫相關的備份恢復、SQL 調優、監控運維、高可用架構設計等。目前任職於愛可生,為各大運營商及銀行金融企業提供 MySQL 相關技術支持、MySQL 相關課程培訓等工作。

在說 Undo 表空間前,先來簡單說下 Undo Log 的概念。

直白來講,Undo Log 是 MySQL 用來記錄事務操作的反方向邏輯日誌。

當確保事務提交成功後,MySQL 後臺有專門的清理線程來清理掉這部分內容,確保 Undo Log 能循環使用。


Undo 的相關概念

  • undo log segment(undo segment)Undo Logs 合集。undo segment 可以被重複使用,但是一次只能由一個事務佔用。
  • rollback segment也就是 Undo Logs 的物理存儲區域。
  • undo tablespacerollback segment 被從系統表空間裡分離出來後的實際磁盤文件表現形式。

所以基本關係如下:

undo log -> undo log segment-> rollback segment->undo tablespace


Undo Log 發展史

MySQL 5.5 和之前的版本

Undo Log 一直存在共享的系統表空間裡(ibdata1...),但有兩個問題:

1. Undo 這塊 IO 處理太集中,無法很好的監測單個瓶頸點

2. 持續併發運行稍微大點的事務,會造成系統表空間持續增大,造成定期的重建系統表空間

MySQL 5.6

Undo Log 被分離出來,由單獨的 Undo 表空間管理。

可以避免 Undo 這塊 IO 消耗過於集中,有助於分散 IO 的負載。

MySQL 5.7

解決了 Undo Log 一直以來物理空間膨脹,無法自動收縮的問題

MySQL 8.0

開始從 SQL 層面非常方便的管理 Undo 表空間


MySQL 8.0 對 Undo Log 的改進說明

1、默認的表空間

MySQL 服務啟動後,默認有兩個 Undo 表空間:undo01,undo02

<code>root@ytt-pc:/var/lib/mysql/3304# ls -sihl undo*919027 14M -rw-r----- 1 mysql mysql 14M 3月  20 11:00 undo_001918943 12M -rw-r----- 1 mysql mysql 12M 3月  20 11:00 undo_002/<code>

這兩個默認產生的 Undo 表空間文件,不能在 SQL 層面來管理。直接刪除會被 MySQL 阻止。

<code>mysql> drop undo tablespace innodb_undo_001;ERROR 3119 (42000): InnoDB: Tablespace names starting with `innodb_` are reserved.mysql> show errors;+-------+------+----------------------------------------------------------------+| Level | Code | Message                                                        |+-------+------+----------------------------------------------------------------+| Error | 3119 | InnoDB: Tablespace names starting with `innodb_` are reserved. || Error | 3119 | Incorrect tablespace name `innodb_undo_001`                    |+-------+------+----------------------------------------------------------------+2 rows in set (0.00 sec)/<code>

2、可設置回滾段數量的參數

參數 innodb_rollback_segments 設置每個 undo 表空間的回滾段的數量。

在 MySQL 5.7 這個參數被用來設置所有 Undo 表空間的回滾段數量。最大 128,就是說一個 MySQL 實例最多 128 個回滾段。

注意高能時刻!

MySQL 8.0 放開了這個限制,使得這個參數設置限制在每個表空間。也就是說每個表空間最多 128 個回滾段,可以設置多個表空間!也就解決了 MySQL 5.7 在持續高併發時,事務爭搶回滾段不足造成的資源搶佔,減少了相關的鎖開銷。

3、自動收縮參數

參數 innodb_undo_log_truncate 默認開啟。開啟這個參數的目的是讓 MySQL 自動收縮 Undo 表空間,防止磁盤佔用過大。

4、廢棄的參數

額外的 Undo 表空間 SQL 層面動態管理參數 innodb_undo_tablespaces 被廢棄。


示例:Undo 表空間管理(不包括臨時表空間)

具體語法:

<code>CREATE [UNDO] TABLESPACE tablespace_nameInnoDB and NDB:[ADD DATAFILE 'file_name']InnoDB only:[FILE_BLOCK_SIZE = value][ENCRYPTION [=] {'Y' | 'N'}]NDB only:USE LOGFILE GROUP logfile_group[EXTENT_SIZE [=] extent_size][INITIAL_SIZE [=] initial_size][AUTOEXTEND_SIZE [=] autoextend_size][MAX_SIZE [=] max_size][NODEGROUP [=] nodegroup_id][WAIT][COMMENT [=] 'string']InnoDB and NDB:[ENGINE [=] engine_name]/<code>

1、創建表空間

語法方面和 MySQL 5.7 創建通用表空間類似,並且是從 MySQL NDB 引擎上借鑑過來的。

創建 Undo 表空間 undo_ts1.ibu

<code>mysql> create undo tablespace undo_ts1 add datafile 'undo_ts1.ibu';Query OK, 0 rows affected (0.47 sec)/<code>

2、查看錶空間

查看 Undo 表空間的元數據信息


information_schema.innodb_tablesapces 表

<code>mysql> select * from information_schema.innodb_tablespaces where SPACE_TYPE='undo'\G*************************** 1. row ***************************        SPACE: 4294967279         NAME: innodb_undo_001         FLAG: 0   ROW_FORMAT: Undo    PAGE_SIZE: 16384ZIP_PAGE_SIZE: 0   SPACE_TYPE: UndoFS_BLOCK_SIZE: 0    FILE_SIZE: 0ALLOCATED_SIZE: 0SERVER_VERSION: 8.0.18SPACE_VERSION: 1   ENCRYPTION: N        STATE: active*************************** 2. row ***************************        SPACE: 4294967278         NAME: innodb_undo_002         FLAG: 0   ROW_FORMAT: Undo    PAGE_SIZE: 16384ZIP_PAGE_SIZE: 0   SPACE_TYPE: UndoFS_BLOCK_SIZE: 0    FILE_SIZE: 0ALLOCATED_SIZE: 0SERVER_VERSION: 8.0.18SPACE_VERSION: 1   ENCRYPTION: N        STATE: active*************************** 3. row ***************************        SPACE: 4294967277         NAME: undo_ts1         FLAG: 0   ROW_FORMAT: Undo    PAGE_SIZE: 16384ZIP_PAGE_SIZE: 0   SPACE_TYPE: UndoFS_BLOCK_SIZE: 0    FILE_SIZE: 0ALLOCATED_SIZE: 0SERVER_VERSION: 8.0.19SPACE_VERSION: 1   ENCRYPTION: N        STATE: active3 rows in set (0.00 sec)/<code>

3、修改存放目錄

Undo 表空間,默認是保存在變量 innodb_undo_directory 指定的目錄,如果這個目錄沒有指定,就放在數據目錄下。

<code># 默認在當前數據目錄mysql> select @@innodb_undo_directory;+-------------------------+| @@innodb_undo_directory |+-------------------------+| ./                      |+-------------------------+1 row in set (0.00 sec)# 剛建立的 undo_ts1.ibu.root@ytt-pc:/var/lib/mysql/3304# ls -sihl undo_ts1.ibu918978 10M -rw-r----- 1 mysql mysql 10M 3月  20 11:33 undo_ts1.ibu/<code>

也可以把 Undo 表空間建立在非 innodb_undo_directory 指定的目錄。

<code># 指定undo 表空間目錄/var/lib/mysql-files/,新建立一個undo_ts2.ibu.mysql> create undo tablespace undo_ts2 add datafile '/var/lib/mysql-files/undo_ts2.ibu';Query OK, 0 rows affected (0.30 sec)/<code>

Undo 表空間的名字必須以 .ibu 為後綴

<code># 創建一個 undo 表空間 undo_ts3,沒有帶後綴,MySQL 拒絕創建。   mysql> create undo tablespace undo_ts3 add datafile 'undo_ts3';   ERROR 3121 (HY000): The ADD DATAFILE filepath must end with '.ibu'.   mysql> show errors;   +-------+------+-------------------------------------------------+   | Level | Code | Message                                         |   +-------+------+-------------------------------------------------+   | Error | 3121 | The ADD DATAFILE filepath must end with '.ibu'. |   | Error | 1528 | Failed to create UNDO TABLESPACE undo_ts3       |   | Error | 3121 | Incorrect File Name 'undo_ts3'.                 |   +-------+------+-------------------------------------------------+   3 rows in set (0.00 sec)/<code>

4、刪除表空間

刪除表空間必須確保這個表空間沒有被任何事務用到,也就是把這個表空間變為非激活狀態,這樣就能阻止任何事務進入這個表空間。

<code>mysql> alter undo tablespace undo_ts2 set inactive;Query OK, 0 rows affected (0.01 sec)mysql> drop undo tablespace undo_ts2;Query OK, 0 rows affected (0.01 sec)/<code>

5、移動表空間

移動 Undo 表空間到其他位置,需要按照這樣的步驟:

1. 停掉 mysqld 服務;

2. 設置參數 innodb_undo_directory 到新的目錄;

3. 移動 Undo 日誌到上一步設置好的目錄;

4. 啟動 mysqld 服務;

步驟 2&3 具體如下:

設置變量 innodb_undo_directory,並且移動 Undo 表空間到這個目錄

<code>mysql> select @@innodb_undo_directory;+-------------------------+| @@innodb_undo_directory |+-------------------------+| /var/lib/mysql-files    |+-------------------------+1 row in set (0.00 sec)/<code>

一切完了後,檢查移動後的 Undo 文件是否正常。

通過檢索文件元數據表 information_schema.files 查看文件類型為 Undo Log 的記錄。系統預留的兩個表空間已經正確的在新目錄下被識別了。

<code>mysql> select file_name,file_type,tablespace_name,status from files where file_type = 'undo log';+-------------------------------+-----------+-----------------+--------+| FILE_NAME                     | FILE_TYPE | TABLESPACE_NAME | STATUS |+-------------------------------+-----------+-----------------+--------+| /var/lib/mysql-files/undo_001 | UNDO LOG  | innodb_undo_001 | NORMAL || /var/lib/mysql-files/undo_002 | UNDO LOG  | innodb_undo_002 | NORMAL |+-------------------------------+-----------+-----------------+--------+2 rows in set (0.00 sec)/<code>

再創建一個新的 Undo 表空間。默認的位置已經變到新的目錄下。

<code>mysql> create undo tablespace undo_ts_new add datafile 'undo_ts_new.ibu';Query OK, 0 rows affected (0.51 sec)root@ytt-pc:/var/lib/mysql-files# ls -l undo*-rw-r----- 1 mysql mysql 10485760 3月  20 12:00 undo_001-rw-r----- 1 mysql mysql 10485760 3月  20 12:00 undo_002-rw-r----- 1 mysql mysql 10485760 3月  20 12:00 undo_ts_new.ibu/<code>


總結

這裡我對 MySQL 8.0 的 Undo 表空間在使用上的改進簡要做了一個說明,可以看出來,MySQL 8.0 對 Undo 的改進已經非常成熟。


分享到:


相關文章: