mysql 记录binlog过程,MySQL的Redo Log、Undo Log和Binlog学习笔记

我们都知道InnoDB的事务由ACID四个特性,其中A原子性由Undo Log来保证,持久性由Redo Log来保证。本片文章记录了Redo Log和Undo Log,以及数据更新流程中Redo Log的两段提交的学习笔记。

Redo Log

Redo Log是物理日志。当发生数据修改时,InnoDB引擎会先将数据写入Redo Log中,并更新内存,此时更新就算完成。同时InnoDB会在合适的时机将记录异写到磁盘。写入的过程如下图:

75c3a1f5b6243376a92e56afe9320d15.png

为了确保每次日志都能写入到事务日志文件中,每次Log Buffer写如文件的过程都会调用操作系统的fsync()。因为MySQL工作在用户空间,Log Buffer处于用户空间内存中。若要写入磁盘中,还要经过内科空间的OS Buffer。此时fsync()就是将日志从OS Buffer写到磁盘的Log File中。

MySQL支持自定义在commit时将日志从Buffer Pool写到Log File中。可通过innodb_flush_log_at_trx_commit来配置,该变量有0、1和2三种,默认为1。具体流程如下图:

c3a8112d188aab8d25708760fedc9a71.png

**0:**事务每次提交,会将内存中日志先写到Log Buffer,再写入OS Buffer,最后每秒异写磁盘;

**1:**事务每次提交,内存中日志直接写入磁盘;

**2:**事务每次提交,先写入OS Buffer,然后每秒异写到磁盘。

如果从安全角度来考虑,配置为1的方式是最安全的,因为每次commit都会直接异写到磁盘,但是IO太多,效率低。

如果使用配置为0或2,性能高但不安全。在0和2中,建议选择2,因为0比2要多义词数据拷贝过程。

关于Redo Log的循环写,假设有这样一组四块儿文件,write pos是当前记录的位置,写完向后移,从ib_logfile_3写到ib_logfile_0。checkpoint是当前删除的位置,也会向后循环删除,当然删除前要先将记录更新到数据文件。

50910f753ba9caafe46b3fa0dbd2a024.png

Undo Log

Undo Log是为了实现事务的原子性,在MySQL数据库的InnoDB存储引擎中,还用Undo Log来实现多版本并发控制。

在操作任何数据之前,首先将数据备份到Undo Log中,然后进行数据修改。如果出现了错误,或用户执行了Rollback语句,系统可以利用Undo Log中的数据恢复到事务开始之前的状态。

Undo Log是逻辑日志,可以理解为:

当delete一条记录时,Undo Log中会记录一条对应的insert记录;

当insert一条记录时,Undo Log会记录一条对应的delete记录;

当update一条记录时,Undo Log会记录一条与之相反的update记录。

Binlog

与Redo Log和Undo Log数据InnoDB不同,Binlog是server层的日志,主要做MySQL功能层面的事。与Redo Log日志的区别如下:

Redo Log是InnoDB独有的,Binlog是所有引擎都可以使用的;

Redo Log是物理日志,记录的是在某个数据页上做了什么修改,Binlog是逻辑日志,记录的是这个语句的原始逻辑;

Redo Log是循环写的,空间会用完。Binlog是可以追加写,不会覆盖之前的日志信息。

关于Binlog的sync_binlog配置:

当sync_binlog = 0时,表示MySQL不控制Binlog的刷新,由文件系统自己控制。此时性能最好,风险最大。遇到crash,binlog_cache的数据都会丢失

当sync_binlog > 0时,表示事务每sync_binlog次提交,MySQL就会将操作写入Binlog文件中。

数据更新流程

执行流程:

执行器先从引擎中找到数据,如果在内存中直接返回,如果不在内存中,查询后返回;

执行器拿到数据之后会先修改数据,然后调用引擎接口重新写入数据;

引擎将数据更新到内存,同时写数据到Redo Log中,此时处于prepare阶段,并通知执行器执行完成,随时可以操作;

执行器生成该操作的Binlog;

执行器调用引擎的事务提交接口,引擎把刚写完的Redo Log改为commit状态,更新完成。

具体流程图如下:

6aa1d975abca408c557fa990e2fdff4d.png

蓝色表示在InnoDB内部执行,红色表示在执行器中执行。需要注意Redo Log的写入被拆分为prepare和commit两个阶段。

Redo Log的两段提交

因为涉及到数据的安全问题,所以要分两个阶段提交。假设现在需要将testColumn从0更新为1,出现了这样两种Crash的情况:

**先写Redo Log再写Binlog:**假设Redo Log写完并且Binlog还没写完的时候,MySQL进程异常重启。Redo Log将testColumn由0恢复为1,但Binlog中没有该记录。之后使用Binlog备份日志的时候,testColumn的值还是0,与原来的值不同;

**先写Binlog后写Redo Log:**假设在Binlog写完后,Redo Log还没写,MySQL进程异常重启。由于Redo Log中没有相应日志,此时库中testColumn值为0,但是使用Binlog恢复的日志中testColumn为1,两者不同。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值