mysql中有三种日志,分别是:

  1. redo log:InnoDB引擎的重做日志,为了事务的持久性
  2. undo log:InnoDB引擎的回滚日志,为了实现事务的原子性
  3. binlog:Mysql Sever的归档日志,用于数据备份和主从同步

下面具体说明各种日志的原理

Redo Log

mysql的数据都存在磁盘中,当操作数据的时候,都需要从磁盘获取,然后在内存里操作,为了提交效率,Mysql通过Buffer Pool来将索引、数据都缓存起来,而在更新的时候,也会先更新Buffer Pool再将更新过的内存数据刷到磁盘中,而为了避免在刷新到磁盘之前宕机之类的故障导致内存数据丢失,在更新内存的时候,也会采用WAL(Write Ahead Logging)技术将数据先写入到日志中,这个日志就是Redo Log。

什么是Redo Log?

redo log是物理日志,记录的是某个数据页做了什么修改,对某个表空间的某个数据页的某个偏移量做了某个更新,每当执行一个事务就会增加一条redo log。

Undo Log

mysql的事务的原子性,就是保证事务要么成功要么失败,失败是需要回滚的,而undo log就是记录了事务提交前的数据,事务回滚时可以利用undo log进行回滚,回滚的方式则不同的操作有不同的策略:

  • insert

    
    将主键值记录下来,如果要回滚则以主键为条件删除
    
  • delete

    
    将待删除数据记录下来,如果要回滚则将数据插入回去
    
  • update

    
    将待更新数据的旧值记录下来,如果要回滚则将数据更新为旧值
    
    

不同操作下 undo log的格式也不一样,但是每一条undo log都有一个roll_pointer指针和一个trx_id事务ID:

  • 通过trx_id可以看出数据是哪个事务变更的
  • 而roll_pointer则可以将undo log串联成一个链表,这个链表称为版本链

undo log还有一个作用:ReadView + undoLog实现MVCC

undo log也是需要记录redo log的,当修改undo页的时候,会先写入到redo log中,再真正修改Undo 页面

RedoLog和UndoLog的区别:

  1. Redo Log是记录操作完成后的数据,事务提交之后崩溃,需要redo log会做故障恢复
  2. Undo Log是记录操作开始前的数据,事务提交之前崩溃,需要通过undo log回滚数据

Redo Log也不是直接写入到磁盘中的,因为每产生一条redo log就写入一次会导致很高的磁盘IO,所以会先写入到redo log buffer中,redo log的刷盘时机:

  • Mysql正常关闭时
  • 事务提交时
  • redo log buffer写入量大于分配的内存空间的一半时
  • 每隔1秒,定时刷盘

redo log有两个文件,当一个log文件满了后会在另一个log文件上继续写入,写满后再切换回来,而且redo log是一个环形结构,写到末尾后又会从开头写。

故障恢复的时候,先执行redo log,将数据恢复到最新状态,同时也会恢复undo log,再将未提交的事务回滚掉。

BinLog

redo log和undo log都是InnoDB存储引擎产生的,而binlog则是server层产生的。

mysql完成一个更新操作后,server会生成一条binlog日志,当事务提交后,该事务产生的binlog会一起写入到binlog文件。

binlog会记录所有数据表结构的变更以及数据的修改,有3种格式:

  • STATEMENT

    
    每一条操作的sql都会记录到binlog中,主从复制中,slave拿到binlog后需要重放sql来同步数据,当sql中含有动态函数时,同步出来的数据可能会不一致
    
  • ROW

    
    记录了每一条数据变更后的样子,如果是修改表机构或者是批量修改的语句,则会产生大量的变更,导致binlog文件过大
    
  • MIXED

    
    根据情况动态选择使用STATEMENT还是ROW
    
    

BinLog的刷盘时机:

  • 事务提交时,会将写入binlog cache的日志持久化到磁盘
  • 当binlog cache写入量达到binlog_cache_size参数规定的大小后会进行刷盘

事务提交时,binlog cache日志持久化到磁盘的方式有3种,由sync_binlog参数控制:

  • sync_binlog=0(默认)

    
    每次提交事务时,只将binlog cache写入到文件缓存,由系统决定什么时候fsync到磁盘
    
  • sync_binlog=1

    
    每次提交时,都将binlog cache写入到文件缓存并执行fsync,将数据刷到磁盘
    
  • sync_binlog=N(N>1)

    
    每次提交时,只将binlog cache写入到文件缓存,积累到N个事务时,执行fsync,将数据刷到磁盘
    
    

RedoLog和BinLog的区别:

  • RedoLog是覆盖写,将文件写满后会从头进行覆盖,BinLog则是追加写,写满了就创建新的文件,不会覆盖之前的数据
  • RedoLog是物理日志,记录的是对数据页的修改,而BinLog则是有3种不同的格式
  • ReadLog用于故障恢复,BinLog用于备份恢复,主从同步

二阶段提交

从上面的介绍中,可以看出,redo log会影响主库数据,binlog会影响从库数据,如果两者不一致的话,会导致主从数据不一致。

为了避免这个问题,mysql采用了二阶段提交的方式:

  • Prepare(准备阶段):将日志写入到redo log,并设置事务为prepare状态
  • Commit(提交阶段):将日志写入binlog,再设置redolog中事务状态为commit

标签: none

添加新评论