mysql体系之redo

什么是redo?

redo log是重做日志,是wal(Write ahead log)的基础.mysql在innodb buffer中修改的数据并不会实时刷新到磁盘,这就全部都是随机的io,性能很差,但是这时候需要redo来保证

数据的持久化。

主要的作用:

1.将随机刷盘转化为顺序刷盘,提高性能

2.crash recovery: 当故障发生导致内存数据丢失后,InnoDB会在重启时,通过重放REDO,将Page恢复到崩溃前的状态

这也是和普通的文件系统最大的区别

redo对我们来说最重要的几个点:

1.性能要高

2.数据一致性,crash recovery数据幂等

然后mysql的redo不像oracle 是物理的,mysql的redo可以说是基于物理的逻辑日志,这个意思就是redo里面记录的是某个page的id及对应的数据的偏移量及对应的字段的值

比(Page ID,Record Offset,(Filed 1, Value 1) … (Filed i, Value i) … )

逻辑的日志有什么问题:

1.就是mysql 默认的page是16K,操作系统是4k,所以就会产生也的分裂,也就是partialpage writes.

比如比如一个事务更新了4k的快,这时候没有double write的时候,操作系统cash了。这时候对于innodb 的 16k数据快来说这是不完整的。这时候启动需恢复的时候发现已经损坏了。

redo的结构?

redom是以ib_logfile0,ib_logfile1来进行命名,

主要的参数就是:

innodb_log_file_in_group:指定redo的个数,默认是2个,具体的可以看官方文档

innodb_log_file_size:每个日志文件指定的文件大小

如果做到高性能?

从大的方便上看让data page延迟刷盘减少随机的磁盘io,从更近一步的看

1.redo的生成,一个redo操作,可能会操作不同page,这时候innodb通过mtr(min-transaction)来保证redo操作的原子性。

mtr.start() 开启一个mini transaction

mtr_x_lock() 加锁,这个操作分成两步,1. 对space->latch加X锁;2. 将space->latch放入mtr_t::m_impl::memo中(这样在mtr.commit()后就可以将mtr之前加过的锁放掉)

mlog_write_ull 写数据,这个操作也分成两步,1. 直接修改page上的数据;2. 将该操作的redo log写入mtr::m_impl::m_log中

mtr.commit() 写redo log + 放锁,这个操作会将上一步m_log中的内容写入redo log file,并且在最后放锁

以上就是一个mtr大致的执行过程,这里仅需要知道mtr.commit()

这是时候就需要考虑到很多mtr操作如何保证在高并发下面的性能

这是可能考虑到redo是需要顺序的,不然如果发现cash 后的recovery会有数据不一致的问题,可能觉得这个会是一个性能的瓶颈点?

虽然看文档8.0开始并发的同步的mtr会调用不同的log_buffer_reseever函数来申请自己的一片log buffer.然后将m_log中的数据拷贝到这片中间。

但是这里想到的就是两个问题:

1.去申请log.sn 申请空间(通过偏移量)的时候应该也是有一把全局的latch

2.并发的写入会有很多的空洞

这部分可以参考:MySQL · 引擎特性 · 庖丁解InnoDB之REDO LOG 不是太理解

大概的理解是:使用link_buf 对lsn取模,相当于分片后,每个m_log里对应的lsn会分散在对应的link_buf段内来提供减少全局的latch,并发的写入

redo 和lsn什么关系?

上面提到mtr中的m_log都有对应的[start_lsn,end_lsn]

去申请log.sn 申请空间。这边redo本省的sn和lsn能进行转换 ,给sn每496B都增加16B的头尾,结果即为对应的lsn

redo和lsn和检查点的关系,需要另一个学习文档展开。

什么时候需要写redo log?

1.每一秒执行

2.事务提交

3.checkpoint

4.binlog切换

5.redo log不足

6.停库

相关的参数

innodb_flush_log_at_trx_commit(重要)

对应的值有 0,1,2

1是最安全的,每次事物提交的时候都会把redo log 直接持久化到磁盘

2每次事物commit的时候只是吧redo log wirte即写入到page cache ,但是持久化到磁盘是每一秒一次。

0日志是每秒执行一次,commit时没有及时写入磁盘。

这里特别提一下percona版本的mysql能session级别的设置这个参数

       1、若innodb_use_global_flush_log_at_trx_commit为OFF,则使用session.innodb_flush_log_at_trx_commit;

  2、若innodb_use_global_flush_log_at_trx_commit为ON,则使用global .innodb_flush_log_at_trx_commit(此时session中仍能设置,但无效)

  3、每个session新建时,以当前的global.innodb_flush_log_at_trx_commit 为默认值

这个值的判断之前看过源码是在mtr_t::Command::execute() 判断。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值