MySQL日志binLog、undoLog和redoLog

背景      

        日志是mysql 数据库的重要组成部分,记录着数据库运行期间各种状态信息。mysql日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。作为开发,我们重点需要关注的是二进制日志(bin log)事务日志(包括redo log和undo log)。

        注意:在数据库系统中,既有存放数据的文件,也有存放日志的文件。

redo log

为什么需要redo log

        我们都知道,事务的四大特性里面有一个是 持久性 ,具体来说就是只要事务提交成功,那么对数据库做的修改就被永久保存下来了,不可能因为任何原因再回到原来的状态 。
        那么 mysql是如何保证一致性的呢?最简单的做法是在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中。但是这么做会有严重的性能问题,主要体现在两个方面:

        1.因为 Innodb 是以  为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这个时候将完整的数据页刷到磁盘的话,太浪费资源了!

        2.一个事务可能涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机IO写入性能太差!

        因此 mysql 设计了 redo log , 具体来说就是只记录事务对数据页做了哪些修改,这样就能完美地解决性能问题了(相对而言文件更小并且是顺序IO)。

        那么数据库的更新操作是一个什么流程呢?

 

redo log基本概念

        redo log是InnoDB存储引擎层的日志,又被称为重写日志,用来记录事务操作的变化,记录的是数据修改之后的值不管事务提交是否成功,都会被记录下来

        当数据库对数据做修改的时候,需要把数据页从磁盘读到buffer pool中,然后在buffer pool中进行修改,那么这个时候buffer pool中的数据页就与磁盘上的数据页内容不一致,称buffer pool的数据页为dirty page 脏页,如果这个时候发生非正常的DB服务重启,那么这些数据还没在内存,并没有同步到磁盘文件中(注意,同步到磁盘文件是个随机IO),也就是会发生数据丢失,如果这个时候,能够在有一个文件,当buffer pool 中的data page变更结束后,把相应修改记录记录到这个文件(注意,记录日志是顺序IO),那么当DB服务发生crash的情况,恢复DB的时候,也可以根据这个文件的记录内容,重新应用到磁盘文件,数据保持一致。

        这种先写日志,后写磁盘的技术就是mysql里面经常提及到的WAL(Write Ahead Logging)技术。

        具体的来说,就是当有一条记录需要更新的时候,InnoDB引擎会把记录优先更新到redo log里面,并更新内存,这样更新操作就完成了。同时,InnoDB引擎会在空闲的时间将redo log中的记录存储到磁盘上(异步写入磁盘)

redo log 记录方式

        由于redo log记录的是数据页的变更,而这种记录是没必要永久保存的,因此redo log实现上采用大小固定,循环写入的方式,当记录写到末尾时,又会从头开始写,如下图所示:

   

        如图所示,write pos是当前记录的位置一边写一边后移,写到4号文件末尾就回到1号文件开头。check point是当前要把记录写入到数据文件的位置,也是后移并且循环的

        写redo log也是需要写磁盘的,但它的好处就是顺序IO(我们都知道顺序IO比随机IO快非常多)。写入的速度很快。

redo log使用场景

        1.redo log写满了,此时MySQL会停止所有更新操作,把脏页刷到磁盘

        2.系统内存不足,需要将脏页淘汰,此时会把脏页刷到磁盘

        3.系统空闲时,MySQL定期将脏页刷到磁盘

        4.用于系统奔溃恢复(crash-safe)。

crash-safe概念

        InnoDB 可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe

        举个列子:当我们修改的时候,写完内存了(buffer),但数据还没真正写到磁盘的时候。此时我们的数据库挂了,我们可以对数据进行恢复。

bin log

bin log基本概念     

        bin log是mysql数据库service层的,是所有存储引擎共享的日志模块,它用于记录数据库执行的写入性操作(存储着每条变更的SQL语句,不包括查询),也就是在事务commit阶段进行记录,一次性将事务中的sql语句以二进制的形式保存于磁盘中

        bin log是逻辑日志,并且由mysql数据库的service层执行,也就是说使用所有的存储引擎数据库都会记录bin log日志。

  • 逻辑日志:可以简单理解为记录的就是sql语句 。

  • 物理日志mysql 数据最终是保存在数据页中的,物理日志记录的就是数据页变更 。

        bin log是以追加的方式进行写入的,可以通过max_binlog_size参数设置bin log文件大小,当文件大小达到某个值时,会生成新的文件来保存日志

bin log刷盘机制        

        对于InnoDB引擎而言,在每次事务`commit`提交时才会记录bin log日志,此时记录仍然在内存中,那么什么时候存储到磁盘中呢?mysql通过 `sync_binlog` 参数控制bin log刷盘时机,取值范围:0~N:

  • 0:不去强求,由系统自行判断何时写入磁盘;
  • 1:每次事务`commit`的时候都要将bin log写入磁盘;
  • N:每N个事务`commit`,才会将bin log写入磁盘;

        sync_binlog参数建议设置为1,这样每次事务commit时就会把bin log写入磁盘中,这样也可以保证mysql异常重启之后bin log日志不会丢失。这也算是mysql 5.7.7之后版本的默认值。

bin log使用场景

        在实际场景中, bin log的主要场景有两点,一点是主从复制,另一点是数据恢复。

  • 主从复制:在master端开启 bin log,然后将 bin log发送给各个slaver端,slaver端读取 bin log 日志,从而使得主从数据库中数据一致
  • 数据恢复:通过 bin log获取想要恢复的时间段数据

undo log

undo log基本概念

        undo log 是回滚日志,是记录每条数据的所有版本,比如 update语句,那么它首先会将该条记录的数据记录到undo log日志中,并且将最新版本的roll_pointer指针指向上一个版本,这样就可以形成当前记录的所有版本,这也是MVCC的实现机制。

bin log和redo log的区别

        1. redo log 是 InnoDB 引擎特有的,binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。binlog会记录所有与MySQL数据库有关的日志记录,包括InnoDB, MyISAM,Heap等其他存储引起的日志。而redo log只记录innodb引擎本身的日志。

        2. redo log 是物理日志,记录的是在某个数据页上做了什么修改。binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如给 ID=2 这一行的 c 字段加 1。

        3. 基于redo log直接恢复数据的效率高于基于binlog sql语句恢复

        4. binlog不是循环使用,在写满或者重启之后,会生成新的binlog文件,redo log是循环使用

        5. binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。

两阶段提交

        MySQL通过两阶段提交来保证redo log和binlog的数据是一致的。当我执行一条 update 语句时,redo log 和 binlog 是在什么时候被写入的呢?

        日志更新流程图:

        写入:redo log(该条记录处于prepare状态)

        写入:binlog

        写入:redo log(该条记录处于commit状态)

        为什么 redo log 要分两个阶段: prepare 和 commit ?redo log 就不能一次写入吗?我们可以先分别看下一次写入会出现的问题。

        1. 先写 redo log,再写 binlog

        这样会出现 redo log 写入到磁盘了,但是 binlog 还没写入磁盘,于是当发生 crash recovery 时,恢复后,主库会应用 redo log,恢复数据,但是由于没有 binlog,从库就不会同步这些数据,主库比从库“新”,造成主从不一致。

        2. 先写 binlog,再写 redo log

        跟上一种情况类似,很容易知道,这样会反过来,造成从库比主库“新”,也会造成主从不一致。

        而两阶段提交,就可以解决掉上述问题。

        当出现crash recovery时,恢复后,如果 redo log 已经 commit,那毫不犹豫的,把事务提交;如果 redo log 处于 prepare,则去判断事务对应的 binlog 是不是完整的;是,则把事务提交;否,则事务回滚。

bin log/redo log/undo log区别

参考文档:

        数据库中的binlog、redolog和undolog有什么用? - 简书

        校招mysql那些事儿|日志模块binlog/redolog/undolog - 知乎

       更新sql的执行过程_行而不辍,未来可期 - King -优快云博客

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值