【MySQL系列】- Redo log知多少

InnoDB 存储引擎是以页为单位来管理存储空间的,我们的增删改查本质上都是对页面上进行操作。我们知道在访问磁盘的时候,MySQL是会把数据加载到Buffer Pool然后进行操作的。对于DML操作,表、索引等的增删改DDL操作,还有数据本身是在Buffer Pool缓冲池中可能还没来得及刷新到磁盘中,系统或者服务器突然崩溃,那这些数据该怎么恢复呢?

redo log是什么

上述问题就需要用到redo log了,那redo log又是什么呢?

官网定义:

A disk-based data structure used during crash recovery, to correct data written by incomplete transactions

翻译过来就是,redo log是一种基于磁盘的数据结构,用于在故障恢复期间纠正由不完整事务写入的数据。

redo log让MySQL innodb引擎有崩溃自动恢复的能力。redo log是保证事务的完整性、持久性,只有innodb引擎支持事务,所以redo log也是innodb引擎独有的。

redo log 格式

redo log本质上只是记录了一下事务对数据库做了哪些修改。InnoDB 针对事务对数据库的不同修改场景定义了多种类型的redo log,但是绝大部分类型的 redo log都有下面这种通用的结构:

【MySQL系列】- Redo log知多少
  • type:redo 日志的类型,redo 日志设计大约有53种不同的类型日志。
  • space ID:表空间 ID
  • page number:页号
  • data:该条 redo 日志的具体内容

mini-transaction

redo log是以组的形式写入磁盘的。插入或者修改一条数据都会对B+树进行修改,可能不止有一个修改点,甚至会涉及到页分裂。为了保证这组数据的原子性,MySQL引入了mini-transaction(简称mtr)的概念。

mtr是当在 DML 操作期间在物理级别对内部数据结构进行更改时,InnoDB 处理的一个内部阶段。mtr没有回滚的概念。一个所谓的mini-Transaction 可以包含一组redo日志,在进行崩溃恢复时这一组redo 日志作为一个不可分割的整体。

一个事务可以包含若干条语句,每一条语句其实是由若干个mini-Transaction组成,每一个 mini-Transaction 又可以包含若干条 redo日志,最终形成了一个树形结构。

LSN

LSN是log sequence number(日志序列号)的缩写,用于记录日志序号,它是一个不断递增的整数。LSN的初始值是8704,也就是说LSN从8704开始递增。每一组由Mini-Transaction生成的redo log都有一个唯一的LSN值与其对应,LSN值越小,说明redo log产生的越早。通过LSN,可以具体地定位到其在redo log文件中的位置。

查看系统中的LSN值

可以通过SQL语句查看系统中LSN的值

SHOW ENGINE INNODB STATUS;

在结果中找到如下片段

---
LOG
---
Log sequence number 1765718166
Log flushed up to   1765718166
Pages flushed up to 1765718166
Last checkpoint at  1765718157
0 pending log flushes, 0 pending chkp writes
212 log i/o's done, 0.00 log i/o's/second
  • Log sequence number:系统中的LSN值,也就是当前系统已经写入的redo日志量,包括写入log buffer中的日志。
  • Log flushed up to:flushed_to_disk_lsn 的值,也就是当前系统已经写入磁盘的 redo 日志量。
  • Pages flushed up to:代表 flush链表中被最早修改的那个页面对应的 oldest_modification 属性值。
  • Last checkpoint at:当前系统的checkpoint_lsn值

Log buffer

为了解决磁盘速度过慢的问题而引入了Buffer Pool。同理,写入 redo log时也不能直接直接写到磁盘上,所以引入了Log buffer。Log buffer(日志缓冲区)是保存要写入磁盘上日志文件的数据的内存区域,Log buffer可通过变量innodb_log_buffer_size配置,默认是16M。Log buffer的数据会定期的刷新到磁盘中,增加日志缓冲区大小可以支持大型事务,这样无需在事务提交之前将redo log写入磁盘,节省磁盘I/O,

InnoDB 为了更好地进行系统崩溃恢复,把通过Mini-Transaction 生成的redo日志都放在了大小为 512 字节的块(block)中,向log buffer中写入 redo log的过程是顺序的,也就是先写入到block中,当该 block的空闲空间用完之后再往下一个 block中写。Mini-Transaction运行过程中产生的一组 redo log,在Mini-Transaction结束时这组redo log会被复制到log buffer 中。

redo log 刷盘时机

前面说到log buffer中的数据会定时刷新到磁盘,这就涉及到redo log 刷盘时机了。可能触发刷盘的情况如下:

  1. log buffer空间不足时:log buffer 的大小是有限的,如果不停地往这个有限大小的 log buffer里写入日志,很快它就会被填满。InnoDB认为如果当前写入log buffer 的 redo log量已经占满了log buffer 总容量的大约一半左右,就需要把这些日志刷新到磁盘上。

  2. 事务提交时:之所以使用redo log主要是因为它占用的空间少,还是顺序写,在事务提交时可以不把修改过的Buffer Pool 页面刷新到磁盘,但是为了保证持久性,必须要把修改这些页面对应的 redo log刷新到磁盘。

    变量innodb_flush_log_at_trx_commit作用于事务提交时,innodb_flush_log_at_trx_commit 变量可配置3个值:

    • 当设置该值为1时,每次事务提交都要做一次刷盘,这是最安全的配置,即使宕机也不会丢失事务;也是默认值
    • 当设置为2时,则在事务提交时只做写操作,只保证写到系统的page cache,因此实例崩溃不会丢失事务,但宕机则可能丢失事务;
    • 当设置为0时,事务提交不会触发redo写操作,而是留给后台线程每秒一次的刷盘操作,因此实例崩溃将最多丢失1秒钟内的事务。
【MySQL系列】- Redo log知多少
不同配置值的持久化程度

显然对性能的影响是随着持久化程度的增加而增加的。通常我们建议在日常场景将该值设置为1,但在系统高峰期临时修改成2以应对大负载。

  1. 后台线程:默认每秒都会刷新一次log buffer中的redo log到磁盘。可以通过变量innodb_flush_log_at_timeout来控制后台线程的刷新频率

  2. 正常关闭服务器时等等

崩溃恢复

在服务器不挂的情况下,redo 日志简直就是个大累赘,不仅没用,反而让性能变得更差。在MySQL 8.0.21版本中,可以通过ALTER INSTANCE DISABLE INNODB REDO_LOG语句来关闭redo Log,最好还是不要关闭,以防万一。万一数据库挂了,就可以在重启时根据redo日志中的记录将页面恢复到系统崩溃前的状态。

MySQL可以根据redo log中的各种LSN值,来确定恢复的起点和终点。然后将 redo log中的数据,以哈希表的形式将一个页面下的放到哈希表的一个槽中。之后就可以遍历哈希表,因为对同一个页面进行修改的 redo log都放在了一个槽里,所以可以一次性将一个页面修复好(避免了多次读取页面的随机I/O)。并且通过各种机制,避免无谓的页面修复,进而提升崩溃恢复的速度。

redo log 参数配置

MySQL的数据目录下默认有两个名为ib_logfile0和ib_logfile1 的文件。可通过以下语句查看数据目录:

SHOW VARIABLES LIKE 'datadir';

redo log的目录和大小都是可修改的。

  • innodb_log_group_home_dir:修改redo log生成目录,默认为当前数据目录所在文件夹下
  • innodb_log_file_size:单个redo log文件的大小,默认是48M
  • innodb_log_files_in_group:redo log文件组的文件个数,默认是2,最大100

redo log在磁盘是以redo log文件组的形式存在的,这些文件的文件名以ib_logfile开头,以数字[N]结尾,N从0开始,N为正整数。

redo log文件是循环写入的,在写入文件时,先写入ib_logfile0,ib_logfile0写满了再写ib_logfile1,以此类推往下写,如果到最后一个文件也写满了,就从ib_logfile0重新开始写。

参考资料:

http://mysql.taobao.org/monthly/2015/05/01/ https://dev.mysql.com/doc/refman/5.7/en/innodb-redo-log.html

推荐阅读:
【MySQL系列】- 浅入Buffer Pool
【MySQL系列】-索引知多少
MySQL MVCC你了解吗


原文始发于微信公众号(索码理):【MySQL系列】- Redo log知多少

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/64162.html

(0)

相关推荐

发表回复

登录后才能评论
半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!