MySQL:binlog 和 redol og

Posted virgosnail

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL:binlog 和 redol og相关的知识,希望对你有一定的参考价值。

【参考文章】:MySQL中Redo与Binlog顺序一致性问题?

【参考文章】:极客时间

1. 数据更新时的日志处理流程

  

1.1 redo log(prepare状态)

  此时SQL已经成功执行了,已经产生了语句的redo和undo内存日志,已经进入了事务commit步骤。然后告诉引擎做Prepare完成第一阶段,Prepare阶段就是写Prepare Log(Prepare Log也是Redo Log),将事务状态设为TRX_PREPARED,写Prepare XID(事务ID号)到Redo Log。写XID到Redo Log的时候会一并把Redo Log刷新到磁盘,这个时候Redo Log的日志量大小取决于执行SQL语句时产生的Redo是否被刷盘,这个刷盘是随机的,后台Master线程每秒钟都会刷新一次。

1.2 binlog

  如果事务涉及的所有存储引擎的Prepare(即Redo Log写入磁盘之后)都执行成功,则调用TC_LOG_BINLOG::log_xid方法将SQL语句写到Binlog(write()将binary log内存日志数据写入文件系统缓存,fsync()将binary log文件系统缓存日志数据永久写入磁盘),同时也会把XID写入到Binlog。此时,事务已经铁定要提交了。否则,调用ha_rollback_trans方法回滚事务,而SQL语句实际上也不会写到binlog。

  Binlog是事务commit时才刷新到磁盘,如果binlog太大则commit时会慢

1.3 redo log(commit状态)

  最后,调用引擎的Commit完成事务的提交。并且会对事务的undo log从prepare状态设置为提交状态(可清理状态),刷新Commit Log到Redo Log,释放锁,释放mvcc相关的read view等等;将事务设为TRX_NOT_STARTED状态。

1.4 两阶段提交

  由上面的二阶段提交流程可以看出,通过两阶段提交方式保证了无论在任何情况下,事务要么同时存在于存储引擎和binlog中,要么两个里面都不存在,可以保证事务的binlog和redo log顺序一致性。一旦阶段2中持久化Binlog完成,就确保了事务的提交。

  此外需要注意的是,每个阶段都需要进行一次fsync操作才能保证上下两层数据的一致性。

  阶段1的fsync由参数innodb_flush_log_at_trx_commit=1控制,阶段2的fsync由参数sync_binlog=1控制,俗称“双1”,是保证CrashSafe的根本。

1.5 CrashSafe

  CrashSafe指mysql服务器宕机重启后,能够保证:

  – 所有已经提交的事务的数据仍然存在。

  – 所有没有提交的事务的数据自动回滚。

2. binlog

  二进制日志是server层的,主要用来做主从复制和即时点恢复时使用的。

2.1 日志记录的三种模式

  基于SQL语句的复制(statement-based replication,SBR):记录执行的SQL语句

  基于行的复制(row-based replication,RBR):记录更新的每一条记录的变化情况

  混合模式复制(mixed-based replication,MBR):根据具体的更新语句选择上述两种中的一种方式记录

2.2 设置 binlog 日志模式 

  静态设置,配置文件形式 

vi my.cnf

    binlog_format="STATEMENT"

  动态设置,命令形式

 mysql> SET GLOBAL binlog_format = \'STATEMENT\';

3. redo log

  事务日志(redo log)是InnoDB存储引擎层的,用来保证事务安全的。

3.1 redo log 文件

  redo log 是固定大小的,从头开始写,写到末尾又回到开头循环写;

  redo log 有两个指针:

  一个为 write pos:表示当前记录的位置,一边写一边后移;

  一个为 checkpoint:表示当前要擦除的位置,一边擦除一边后移,擦除之前要将记录写到磁盘文件中;

4. 区别

  binlog 属于MySQL的 sever 层,所有引擎都可以使用;redo log 属于 InnoDB引擎特有。

  binlog 是逻辑日志,记录的是SQL语句的原始逻辑;redo log 是物理日志,记录的是在某个数据页上做了什么修改。

  binlog 是追加写,一个文件写满之后就写到下一个文件,不会覆盖之前的文件;redo log 是循环写,写到文件末尾之后又从文件起始位置开始写,会覆盖之前的日志。

5. 故障恢复

  开启Binary log的MySQL在crash recovery时:MySQL在prepare阶段会生成xid,然后会在commit阶段写入到binlog中。在进行恢复时事务要提交还是回滚,是由Binlog来决定的

  – 事务的Xid_log_event存在,就要提交。

  – 事务的Xid_log_event不存在,就要回滚。

恢复的过程非常简单:

  – 扫描最后一个Binlog文件(进行rotate binlog文件时,确保老的binlog文件对应的事务已经提交),提取其中的Xid_log_event

  – 重做检查点以后的redo日志,读取事务的undo段信息,搜集处于prepare阶段的事务链表,将事务的xid与binlog中的xid对比,若存在,则提交,否则就回滚

总结一下,基本顶多会出现下面是几种情况:

  • 当事务在prepare阶段crash,数据库recovery的时候该事务未写入Binary log并且存储引擎未提交,将该事务rollback。
  • 当事务在binlog阶段crash,此时日志还没有成功写入到磁盘中,启动时会rollback此事务。
  • 当事务在binlog日志已经fsync()到磁盘后crash,但是InnoDB没有来得及commit,此时MySQL数据库recovery的时候将会读出二进制日志的Xid_log_event,然后告诉InnoDB提交这些XID的事务,InnoDB提交完这些事务后会回滚其它的事务,使存储引擎和二进制日志始终保持一致。

  总结起来说就是如果一个事务在prepare阶段中落盘成功,并在MySQL Server层中的binlog也写入成功,那这个事务必定commit成功。

以上是关于MySQL:binlog 和 redol og的主要内容,如果未能解决你的问题,请参考以下文章

Mysql两阶段提交详解

聊聊redo log是什么?

聊聊redo log是什么?

聊聊redo log是什么?

聊聊redo log是什么?

在哪里可以找到 MySQL 事务日志?