学习小记 -- Mysql事务日志(redo log)

3 篇文章 0 订阅
2 篇文章 0 订阅

目录

redo log

log block

log group

redo log的格式


最近又把事务仔细盘了一遍,防止忘记,赶紧记下来,嘿嘿😁😁😁~

我们都知到,InnoDB中的事务符合ACID的特性:

  • 原子性(atimicity)
  • 一致性(consistency)
  • 隔离性(ioslation)
  • 持久性(durability)

这里就不详细展开描述概念了,事务的隔离性由之前写到的mysql中的锁来控制。原子性、一致性、持久性通过数据库的redo logundo log来完成。redo log称为重做日志,用来保证事务的原子性和持久性。undo log用来保证事务的一致性。

redo log

redo log是"物理日志", 记录的是具体数据页上做了什么修改,用来实现事务的持久性,适用于崩溃恢复。它不是随着事务的提交才写入的,而是在事务的执行过程 中,便开始写入 redo 中。

redo log由两部分组成,重做日志缓冲redo log buffer(易失的),和重做日记缓冲文件(redo log file),是持久性的。

innoDB 通过Force Log at Commit机制实现事务的持久性,当事务提交commit时,必须将该事务的所有日志写入到重做日志文件进行持久化,待事务的commit操作完成才算完成。

为了确保每次日志都写入重做日志文件,在每次将rdo log buffer写入redo log file后,innoDB存储引擎都会调用一次操作系统的fsync操作。因为MySQL是工作在用户空间的,MySQL的log buffer处于用户空间的内存中。要写入到磁盘上的log file中(redo:ib_logfileN文件,undo:share tablespace或.ibd文件),中间还要经过操作系统内核空间的os buffer,调用fsync()的作用就是将OS buffer中的日志刷到磁盘上的log file中。

如下图:

注意:一般所说的log file并不是磁盘上的物理日志文件,而是操作系统缓存中的log file,官方是这么说的

这不太好理解,既然都称为file了,应该已经属于物理文件了。所以在本文后续内容中都以os buffer来表示官方手册中所说的Log file,然后log file则表示磁盘上的物理日志文件,即log file on disk

innoDB通过参数innodb_flush_log_at_trx_commit来控制重做日志刷新到磁盘的策略。

该变量有3种值:0、1、2,默认为1。但这个变量只是控制commit动作是否刷新log buffer到磁盘。

  • 当设置为1的时候,事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file on disk中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。
  • 当设置为0的时候,事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file on disk中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。
  • 当设置为2的时候,每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。当操作系统宕机时,重启数据库后会丢失未从os buffer刷新到log buffer的那部分数据。

那么0、1、2这三个参数哪个对性能影响最大呢?我这里就不做测试了,网上有很多大佬做的数据参考,这里直接采用他们得到的结果,其实0和2的差距并不太大,但值为1的性能却差太多。但2却比0要安全的多。它们都是每秒从os buffer刷到磁盘,它们之间的时间差体现在log buffer刷到os buffer上,因为将log buffer中的日志刷新到os buffer只是内存数据的转移,并没有太大的开销。而1造成时间比较长的原因就在于fsync操作比较耗时。

尽管设置为0和2可以大幅度提升插入性能,但是在故障的时候可能会丢失1秒钟数据,这1秒钟很可能有大量的数据,更好的插入数据的做法是将值设置为1,然后修改存储过程,将每次循环都提交修改为只提交一次(都插入最后进行提交)这样既能保证数据的一致性,也能提升性能。

log block

innodb存储引擎中,redo log以块为单位进行存储的,每个块占512字节,这称为redo log block。所以不管是log buffer中还是os buffer中以及redo log file on disk中,都是这样以512字节的块存储的。

redo log block 除了日志本身之外,还由日志块头(log block header),日志块尾(log block tailer)组成,日志块头占12字节,日志块尾占用8字节,所以每个redo log block可以存储的大小为492字节。在redo log buffer中的结构如下图:

  • log_block_hdr_no:(4字节)该日志块在redo log buffer中的位置ID。
  • log_block_hdr_data_len:(2字节)该log block中已记录的log大小。写满该log block时为0x200,表示512字节。
  • log_block_first_rec_group:(2字节)该log block中第一个log的开始偏移位置。
  • lock_block_checkpoint_no:(4字节)写入检查点信息的位置。

如果事务T1的redo log占用592字节,事务T2占用100字节,而一个log block最多只能保存492个字节,所有事务T1要占用2个log block,在第二个log block header中,log_block_first_rec_grou的值为112(100+12)。

若一个log block header中 log_block_hdr_data_le=log_block_first_rec_group,则表示当前log block中不包含新的日志。

log block tailer只有1个部分组成,其值和 log_block_hdr_no相同。

log group

log group是一个逻辑上的概念,组内redo log file的数量由变量 innodb_log_files_group 决定,默认值为2,即两个redo log file。

在innodb将log buffer中的redo log block刷到这些log file中时,会以追加写入的方式循环轮训写入。即先在第一个log file的尾部追加写,直到满了之后向第二个log file写。当第二个log file满了会清空一部分第一个log file继续写入。

redo log file 除了保存log buffer 刷新到磁盘的log block,还保留了一些其他信息,这些信息一共占用了2KB,从2KB之后才开始记录log block,而且这些信息只保存在第一个log file中,在第二个log file 中会将这2KB的空间空出来。

redo log的格式

由于InnoDB存储引擎的管理是基于页的,所以redo log格式也是基于页的,redo log 头的格式如下:

  •  redo log type:redo log的类型
  • space:表空间的ID
  • page_no:页的偏移量

redo log body根据redo log类型的不同,存储的内容不同。

如下图,分别是insert和delete大致的记录方式。

参考 :

1.《MySQL技术内幕--InnoDB存储引擎》

2. https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html#auto_id_0 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值