本文共 6282 字,大约阅读时间需要 20 分钟。
InnoDB的undo log从5.6版本开始可以存储到单独的tablespace文件中,在5.7版本支持了在线undo文件truncate,解决了长期以来的undo膨胀问题。而到了8.0版本,对Undo tablespace做了进一步的优化:在新版本中,我们可以拥有更多的回滚段(每个Undo tablespace可以有128个回滚段,而在之前的版本中所有tablespace的回滚段不允许超过128个),减少了由于事务公用回滚段产生的锁冲突;可以在线动态的增删undo tablespace,使得undo的管理更加灵活。
在最近release的8.0.14版本中,开始支持SQL接口来创建,修改和删除 (undo space的管理不记录binlog)。可以预见未来将逐步废弃根据配置innodb_undo_tablespaces来创建undo tablespace, 通过SQL接口来创建undo tablespace将是唯一的接口。实际上在最新版本中已经将参数innodb_undo_tablespaces标记为deprecated状态,用户应尽量避免依赖该参数。
在安装实例时,会默认创建两个undo tablespace:
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE ROW_FORMAT = 'Undo'\G*************************** 1. row *************************** SPACE: 4294967279 NAME: innodb_undo_001 FLAG: 0 ROW_FORMAT: Undo PAGE_SIZE: 16384 ZIP_PAGE_SIZE: 0 SPACE_TYPE: Undo FS_BLOCK_SIZE: 0 FILE_SIZE: 0ALLOCATED_SIZE: 0SERVER_VERSION: 8.0.15 SPACE_VERSION: 1 ENCRYPTION: N STATE: active*************************** 2. row *************************** SPACE: 4294967278 NAME: innodb_undo_002 FLAG: 0 ROW_FORMAT: Undo PAGE_SIZE: 16384 ZIP_PAGE_SIZE: 0 SPACE_TYPE: Undo FS_BLOCK_SIZE: 0 FILE_SIZE: 0ALLOCATED_SIZE: 0SERVER_VERSION: 8.0.15 SPACE_VERSION: 1 ENCRYPTION: N STATE: active2 rows in set (0.00 sec)mysql> SHOW GLOBAL STATUS LIKE '%UNDO_TABLESPACE%';+----------------------------------+-------+| Variable_name | Value |+----------------------------------+-------+| Innodb_undo_tablespaces_total | 2 || Innodb_undo_tablespaces_implicit | 2 || Innodb_undo_tablespaces_explicit | 0 || Innodb_undo_tablespaces_active | 2 |+----------------------------------+-------+4 rows in set (0.00 sec)
你可以通过如下语句来创建独立的undo tablespace, 文件后缀必须以ibu结尾。新创建的tablespace为active状态
mysql> CREATE UNDO TABLESPACE myundo ADD DATAFILE 'myundo.ibd';ERROR 3121 (HY000): The ADD DATAFILE filepath must end with '.ibu'.mysql> CREATE UNDO TABLESPACE myundo ADD DATAFILE 'myundo.ibu';Query OK, 0 rows affected (0.26 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE ROW_FORMAT = 'Undo' and NAME = 'myundo'\G*************************** 1. row *************************** SPACE: 4294967277 NAME: myundo FLAG: 0 ROW_FORMAT: Undo PAGE_SIZE: 16384 ZIP_PAGE_SIZE: 0 SPACE_TYPE: Undo FS_BLOCK_SIZE: 0 FILE_SIZE: 0ALLOCATED_SIZE: 0SERVER_VERSION: 8.0.15 SPACE_VERSION: 1 ENCRYPTION: N STATE: active --> 此时状态为active1 row in set (0.01 sec)
在创建undo space时,你可以使用绝对路径,也可以放在实例配置的undo目录下,但要注意一点:在崩溃恢复前undo space必须要能够被发现并打开,但这时候Innodb data dictionary还是处于不可用的状态,我们无法从其中获取准确的文件位置,只有--datadir, --innodb-home-directory, --innodb-undo-directory 和 --innodb-directories会被扫描掉,如果你放在其他地方,就可能造成找不到该tablespace, 导致实例数据不一致。
相关代码:
为undo tablespace预留的space id (但最多依然是127个undo tablespace, 每个space number会给一个范围内的space id, 默认512个id):
InnoDB入口函数: innodb_create_undo_tablespace
如果你不想使用某个Undo tablespace,可以将其设置为inactive状态, 但需要保证至少有连个active的undo tablespace, 这个限制的原因是:当一个undo tablespace正在被truncate时,至少有一个是可用的。
当被设置为Inactive状态之后,事务就不会从其中分配回滚段。
mysql> ALTER UNDO TABLESPACE myundo SET INACTIVE;Query OK, 0 rows affected (0.01 sec)
相关代码:
Sql_cmd_alter_undo_tablespace
apply_dd_undo_state()
)innodb_alter_undo_tablespace--> innodb_alter_undo_tablespace_active
innodb_alter_undo_tablespace --> innodb_alter_undo_tablespace_inactive
在删除一个undo tablespace之前,首先要把undo tablespace设置为inactive状态
mysql> DROP UNDO TABLESPACE myundo;ERROR 1529 (HY000): Failed to drop UNDO TABLESPACE myundomysql> ALTER UNDO TABLESPACE myundo SET INACTIVE;Query OK, 0 rows affected (0.01 sec)mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE ROW_FORMAT = 'Undo' and Name = 'myundo'\G*************************** 1. row *************************** SPACE: 4294967150 NAME: myundo FLAG: 0 ROW_FORMAT: Undo PAGE_SIZE: 16384 ZIP_PAGE_SIZE: 0 SPACE_TYPE: Undo FS_BLOCK_SIZE: 0 FILE_SIZE: 0ALLOCATED_SIZE: 0SERVER_VERSION: 8.0.15 SPACE_VERSION: 1 ENCRYPTION: N STATE: empty --> 此时undo space内没有任何Undo log, 已经是empty可删除状态1 row in set (0.00 sec)mysql> DROP UNDO TABLESPACE myundo;Query OK, 0 rows affected (0.02 sec)
即使状态为inactive的,但要保证如下几点才能被删除:
如果undo tablespace非空,在drop时,会返回错误码HA_ERR_TABLESPACE_IS_NOT_EMPTY. 所以在设置为inactive到真正可以删除可能存在时间差,我们可以通过监控INFORMATION_SCHEMA.INNODB_TABLESPACES中的undo space状态是否为empty来判定是否可以删除。 Note:系统创建的Undo space不允许被删除
相关代码:
Sql_cmd_drop_undo_tablespace
InnoDB 入口函数: innodb_drop_undo_tablespace
事务提交后,执行post ddl (Log_DDL::replay_delete_space_log
)
当参数innodb_undo_log_truncate打开时,所有隐式和显式创建的Undo tablespace都会在满足一定条件时被purge线程truncate掉. 当参数关闭时,则只有将Undo tablespace设置为Inactive状态时才会去truncate tablespace。 因此如果你想自己控制undo truncation, 可以关闭参数,在监控undo tablespace的大小,通过SET INACTIVE触发truncation, 再通过SET ACTIVE激活undo space。
相关代码:
trx_purge_truncate_marked_undo_low
trx_undo_truncate_tablespace:
undo::use_next_space_id(space_num)
fil_replace_tablespace
: 删除当前undo space,重建文件并设置为新的space id为何需要新的space id ? 这是因为在删除重建文件的过程中我们没有做checkpoint,这时候如果crash掉,有些redo log可能需要修改一些已经不存在的page,导致崩溃恢复时候(ref: )
转载地址:http://ulykl.baihongyu.com/