ITPub博客

首页 > 数据库 > MySQL > mysql undo管理

mysql undo管理

原创 MySQL 作者:czxin788 时间:2018-01-10 16:00:58 0 删除 编辑
mysql undo管理
声明:本文内容是笔者阅读《MySQL运维内参》后整理的笔记

innodb支持的回滚段总共有128*1024=131072个。

在事务的执行过程中,会产生两种回滚日志,一种是insert的undo日志,一种是update的undo日志。可能有人会问,delete哪里去了。其实是包含在update回滚日志中的。
因为innodb把undo分为两类:一类是新增,也就是insert,一类是修改,也就是update。分类的依据就是commit后要不要做purge操作,因为insert是不需要purge的,只要事务提交了,那个回滚日志就可以丢掉了;而对于更新和删除操作,如果事务提交了,还需要为MVCC服务,那就需要将这些日志放到history list中去,等待去做purge或MVCC的多版本查询等。

通常情况下,如果一个事务既有插入,又有更新(或删除),那么这个事务对应两个UNDO段,即在一个rseg的1024个槽中,要使用两个槽来存储事务的回滚段,一个是插入段,一个是更新段。


在事务要存储回滚记录的时候,事务就要从1024个槽中,根据相应的更新类型(插入或者更新)找到空闲的槽做为自己的UNDO段。如果已经申请过相同类型的undo段,就直接使用,否则就需要创建一个段,并将段首页号写入这个rseg长度为1024的数组多赢的空闲位置中去。

如果在1024个槽中,找不到空间的位置,那么这个事务就被回滚掉,报出错误“too many active concurrent transactions”,错误号为1637的异常。当然,这种情况一般不会见到,如果能把这个用完,估计数据库已经根本动不了了。

回滚时刻:在数据库的启动过程中,先进行redo日志恢复,然后才进行undo的操作。
                   mysql是根据innodb_force_recovery来决定要不要做回滚操作,如果设置为3或3以上,就不需要回滚了,这可能会导致数据库逻辑上的不一致。

因为undo是反向操作,所以应该是先处理新产生的事务,后处理老的事务,通过事务号区分新老关系。也就是说,innodb是通过从大到小的顺序遍历。

针对每一个undo段,innodb会将所有的状态为ACTIVE的事务的undo日志扫描出来,然后一条一条的做回滚操作。

InnoDB支持128个undo logs,这里特别说明下,从5.7开始,innodb_rollback_segments的名字改成了innodb_undo_logs,但表示的都是回滚段的个数。 


我们先大致看下InnoDB的undo在不同的版本上的一些演进:

MySQL 5.5的版本上 
InnoDB undo是放在系统表空间即ibdata file文件中,这样如果有比较大的事务(即需要生成大量undo的),会撑大ibdata数据文件,
虽然空间可以重用, 但文件大小不能更改。 
关于回滚段的,只有这个主要的参数,用来设置多少个rollback segment。

[html] view plain copy
mysql> show global variables like '%rollback_segment%';  
+----------------------------+-------+  
| Variable_name              | Value |  
+----------------------------+-------+  
| innodb_rollback_segments  | 128  |  
+----------------------------+-------+  
MySQL 5.6的版本上 
InnoDB undo支持独立表空间, 增加如下参数:

[html] view plain copy
+-------------------------+-------+  
| Variable_name          | Value |  
+-------------------------+-------+  
| innodb_undo_directory  | .    |  
| innodb_undo_logs        | 128  |  
| innodb_undo_tablespaces | 1    |  
+-------------------------+-------+  
这样,在install的时候,就会在data目录下增加undo数据文件,来组成undo独立表空间,但文件变大之后的空间回收还是成为问题。

MySQL 5.7的版本上 

InnoDB undo在支持独立表空间的基础上,支持表空间的truncate功能,增加了如下参数:

[html] view plain copy
mysql> show global variables like '%undo%';                                                                                +--------------------------+------------+  
| Variable_name            | Value      |  
+--------------------------+------------+  
| innodb_max_undo_log_size | 1073741824 |  
| innodb_undo_directory    | ./        |  
| innodb_undo_log_truncate | OFF        |  
| innodb_undo_logs        | 128        |  
| innodb_undo_tablespaces  | 3          |  
+--------------------------+------------+  
mysql> show global variables like '%truncate%';  
+--------------------------------------+-------+  
| Variable_name                        | Value |  
+--------------------------------------+-------+  
| innodb_purge_rseg_truncate_frequency | 128  |  
| innodb_undo_log_truncate            | OFF  |  
+--------------------------------------+-------+  
InnoDB的purge线程,会根据innodb_undo_log_truncate开关的设置,和innodb_max_undo_log_size设置的文件大小阈值,以及truncate的频率来进行空间回收和rollback segment的重新初始化。

注释:
innodb_undo_log_truncate参数设置为1,即开启在线回收(收缩)undo log日志文件,支持动态设置。

innodb_undo_tablespaces参数必须大于或等于2,即回收(收缩)一个undo log日志文件时,要保证另一个undo log是可用的。

innodb_undo_logs: undo回滚段的数量, 至少大于等于35,默认128。

innodb_max_undo_log_size:当超过这个阀值(默认是1G),会触发truncate回收(收缩)动作,truncate后空间缩小到10M。

innodb_purge_rseg_truncate_frequency:控制回收(收缩)undo log的频率,表示purge undo轮询128次后,进行一次undo的truncate。undo log空间在它的回滚段没有得到释放之前不会收缩,想要增加释放回滚区间的频率,就得降低innodb_purge_rseg_truncate_frequency设定值。

innodb_undo_directory:undo文件存放的位置;



默认情况下, 是purge触发128次之后,进行一次rollback segment的free操作,然后如果全部free就进行一个truncate。
当设置innodb_undo_log_truncate=ON的时候, undo表空间的文件大小,如果超过了innodb_max_undo_log_size, 就会被truncate到初始大小,但有一个前提,就是表空间中的undo不再被使用。

注意: 
如果是在线库,要注意影响,因为当一个undo tablespace在进行truncate的时候,不再承担undo的分配。只能由剩下的undo 表空间的rollback segment接受事务undo空间请求。

MySQL 5.7 设置undo为独立表空间

MySQL5.7中开始支持把undo log分离到独立的表空间,并放到单独的文件目录下;采用独立undo表空间,再也不用担心undo会把 ibdata1 文件搞大,还可以自动收缩空间;
也给我们部署不同IO类型的文件位置带来便利,对于并发写入型负载,我们可以把undo文件部署到单独的高速存储设备上. 

在数据库初始化的时候就使用如下几个参数,就可以分离出单独的undo表空间
(root@localhost)[(none)]> show variables like '%undo%';
+--------------------------+--------------+
| Variable_name            | Value        |
+--------------------------+--------------+
| innodb_max_undo_log_size | 104857600    |
| innodb_undo_directory    | /log/undolog |
| innodb_undo_log_truncate | ON          |
| innodb_undo_logs        | 128          |
| innodb_undo_tablespaces  | 3            |
+--------------------------+--------------+
5 rows in set (0.01 sec)

(root@localhost)[(none)]> show variables like '%truncate%';
+--------------------------------------+-------+
| Variable_name                        | Value |
+--------------------------------------+-------+
| innodb_purge_rseg_truncate_frequency | 128  |
| innodb_undo_log_truncate            | ON    |
+--------------------------------------+-------+


show status like 'Innodb_available_undo_logs';
无法动态修改:
root@localhost [(none)]> set global innodb_undo_tablespaces=3;
ERROR 1238 (HY000): Variable 'innodb_undo_tablespaces' is a read only variable

已安装数据库不能修改 innodb_undo_tablespaces 
2016-03-24 16:27:18 7164 [Note] InnoDB: Using Linux native AIO
2016-03-24 16:27:18 7164 [Note] InnoDB: Using CPU crc32 instructions
2016-03-24 16:27:18 7164 [Note] InnoDB: Initializing buffer pool, size = 100.0M
2016-03-24 16:27:18 7164 [Note] InnoDB: Completed initialization of buffer pool
2016-03-24 16:27:18 7fb591068720 InnoDB: Expected to open 3 undo tablespaces but was able
2016-03-24 16:27:18 7fb591068720 InnoDB: to find only 0 undo tablespaces.
2016-03-24 16:27:18 7fb591068720 InnoDB: Set the innodb_undo_tablespaces parameter to the
2016-03-24 16:27:18 7fb591068720 InnoDB: correct value and retry. Suggested value is 0
2016-03-24 16:27:18 7164 [ERROR] Plugin 'InnoDB' init function returned error.
2016-03-24 16:27:18 7164 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
2016-03-24 16:27:18 7164 [ERROR] Unknown/unsupported storage engine: InnoDB
2016-03-24 16:27:18 7164 [ERROR] Aborting

---the end

参考文档:
《MySQL运维内参》一书
http://blog.chinaunix.net/uid-31396856-id-5753413.html


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/28916011/viewspace-2149989/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2014-06-03

  • 博文量
    233
  • 访问量
    858428