MySQL 5.7 新特性:在线truncate undo log文件

在MySQL5.7.5版本中,增加了一个比较有用的功能,即用户可以自己truncate掉undo log。 对应的changeling entry如下:

InnoDB: You can now truncate undo logs that reside in undo tablespaces. This feature is enabled using theinnodb_undo_log_truncate configuration option. For more information, see Truncating Undo Logs That Reside in Undo Tablespaces.

我们知道Undo log是MVCC多版本控制的核心模块,一直以来undo log都存储在ibdata系统表空间中,而从5.6开始,用户可以把undo log存储到独立的tablespace中,并拆分成多个Undo log文件。 但5.6及5.6之前的版本都无法缩小文件的大小。而长时间未提交事务导致大量undo 空间的浪费的例子,在我们的生产场景也不是一次两次了。

5.7的undo log的truncate操作是基于独立undo 表空间来实现的

0.相关参数

在能够使用该特性之前,需要先打开独立undo表空间,注意现在只能在install db的时候才能开启,因为他在初始化阶段是写死占用了最小的几个space id的…这种实现方式。。。只能无限吐槽 了- -..
有几个参数控制undo tablespace:
innodb_undo_directory: Undo文件的存储目录
innodb_undo_tablespaces: undo tablespace的个数,至少大于等于2,因为在truncate一个undo log文件时,要保证另外一个是可用的,这样就无需停止业务了.
innodb_undo_logs: undo回滚段的数量, 至少大于等于35,默认128.官方博客对35这个数字的解释:

The value of 35 comes from how the UNDO logs (rollback segments or rsegs) are allocated—0: REDO enabled rseg allocated in the system tablespace, 1-32: non-REDO enabled rsegs allocated in the temporary tablespace, 33-n: REDO enabled rsegs allocated in UNDO table spaces

0         -> rseg resides always in system tablespace
1..32  -> rseg resides in shared temporary tablespace (ibtmp1)

33     -> undo-tablespace-0
34     -> undo-tablespace-1
….
33+n-1 -> undo-tablespace-n-1 (undo tablespace indexes from 0 so n-1 is last).
33+n   -> undo-tablespace-0
33+n+1 -> undo-tablespace-1
….
m      -> undo-tablespace-x

innodb_purge_rseg_truncate_frequency: 用于控制purge回滚段的频度.

innodb_max_undo_log_size: 控制最大undo tablespace文件的大小,超过这个阀值时才会去尝试truncate. truncate后的大小默认为10M

打开/关闭该特性,使用动态参数innodb_undo_log_truncate控制

root@(none) 06:43:29>set global innodb_undo_log_truncate = ON;
Query OK, 0 rows affected (0.00 sec)

root@(none) 06:43:32>set global innodb_undo_log_truncate = OFF;
Query OK, 0 rows affected (0.00 sec)

下面简单介绍下实现的相关代码
0.新的truncate管理结构体

新的类undo::Truncate被引入,来管理table space truncate的过程
挂在purge_sys->undo_trunc中

1.标记需要truncate的undo tablespace

这个动作实际上是由purge的协调线程发起的,默认情况下每做128次purge后,会调用函数trx_purge_truncate进行清理操作,我们只关心truncate,对应的调用栈为:
trx_purge_truncate
|—>trx_purge_truncate_history
|—>trx_purge_mark_undo_for_truncate
|—>trx_purge_initiate_truncate

trx_purge_mark_undo_for_truncate 是标记truncate undo表空间的入口函数,主要包括如下步骤
step1: 检查是否开启truncate参数,或者已经有table space已经被标记为truncate

step2:检查是否可以进行安全的truncate,也就是上面说的innodb_undo_tablespaces>=2,  innodb_undo_logs>=35

step3:从上次扫描的tablespace开始遍历(round-robin),哪些tablespace可以标记为可truncate,如果发现一个需要truncate的 tablespace,则标记其为需要truncate,并从遍历中break出来:
undo_trunc->mark(space_id);
undo::Truncate::add_space_to_trunc_list(space_id);

step4: 遍历被选中的table space中的回滚段,将其设置为不可分配,判断条件为:

917                 if (rseg != NULL && !trx_sys_is_noredo_rseg_slot(rseg->id)) {
918                         if (rseg->space
919                                 == undo_trunc->get_marked_space_id()) {
920
921                                 /* Once set this rseg will not be allocated
922                                 to new booting transaction but we will wait
923                                 for existing active transaction to finish. */
924                                 rseg->skip_allocation = true;
925                                 undo_trunc->add_rseg_to_trunc(rseg);
926                         }
927                 }

2. truncate operation

在标记需要truncate的tablespace后,需要先检查需要删除的回滚段是否是可释放的。也就是没有任何活跃的事务会应用到其中的Undo log

入口函数:trx_purge_initiate_truncate

step 1: 检查回滚段是否可释放,如果不可以(有活跃事务可能使用undo做MVCC),直接返回

step 2:做一次redo checkpoint,因为如果随后发生crash,可能针对该undo tablespace的redo 就会无效了,因为文件被truncate了。
log_make_checkpoint_at(LSN_MAX, TRUE);  这会刷新所有脏页和redo log.

step 3.开始之前…
1100                 undo_trunc->start_logging(
1101                         undo_trunc->get_marked_space_id());

创建一个命名为undo_<space_id>_trunc.log的文件,如果crash重启发现该文件,则表明truncate tablespace可能没有完成,需要重做.

step 4: 清理对应的purge queue,无需继续做Purge 操作
trx_purge_cleanse_purge_queue(undo_trunc);

step5 : 执行真正的truncate

bool    success = trx_undo_truncate_tablespace(undo_trunc);

入口函数:trx_undo_truncate_tablespace
..truncate文件
success = fil_truncate_tablespace(
space_id, SRV_UNDO_TABLESPACE_SIZE_IN_PAGES);

文件先被truncate到0,再重新设置到10M,相当于一个新建的undo tablespace.

…重新初始化undo log tablespace的头,这个过程不记录redo log.
fsp_header_init(space_id, SRV_UNDO_TABLESPACE_SIZE_IN_PAGES, &mtr);

…重新初始化该tablespace内的回滚段头

step 6:在完成truncate后,再做一次checkpoint

step 7: 完成后
undo_trunc->done_logging(undo_trunc->get_marked_space_id());

删除undo_<space_id>_trunc.log

step 8: 清理操作

undo_trunc->reset();
undo::Truncate::clear_trunc_list();

worklog:
http://dev.mysql.com/worklog/task/?id=6965

相关代码:
http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8631
http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8629
http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8622
http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8615

官方博客描述:
http://mysqlserverteam.com/online-truncate-of-innodb-undo-tablespaces/

 

原创文章,转载请注明: 转载自Simple Life

本文链接地址: MySQL 5.7 新特性:在线truncate undo log文件

Post Footer automatically generated by wp-posturl plugin for wordpress.


Comments

Leave a Reply

Your email address will not be published. Name and email are required


Current month ye@r day *