binlog,redolog,undolog Mysql三种日志的作用和区别

Mysql有三种很重要的日志也是面试经常涉及到的考点,分别是 binlog 、redo log和undo log,这里面binlog 是server层实现的日志 , 而redo log 和undo log都是引擎层(innodb)实现的日志 。也正是因为它们在Mysql不同的体系结构里 , 所以他们所针对的问题也是完全不同的,下面我们就来详细讲解下这三种日志的作用以及它们之间的区别 。
一、什么是redo log (重做日志又称为前滚日志)我们知道 MySQL 数据存在磁盘中,每次读写数据需做磁盘随机IO,并发场景下性能差 。为此 MySQL 引入缓存 Buffer Pool 做优化 。其包含磁盘中部分数据页(page)的映射,来缓解数据库的磁盘压力 。
当从数据库读数据时 , 首先从缓存中读,缓存中没有,则从磁盘读后放入缓存;当向数据库写数据时,先向缓存中写,此时缓存中的数据页数据会变更,该数据页叫脏页,Buffer Pool 中修改完数据后会按照设定的策略再定期刷到磁盘中去 , 这个过程叫刷脏页 。
那么问题来了,如果 Buffer Pool 中修改的数据还没有及时的刷到磁盘,MySQL 宕机重启 , 就会导致数据丢失,无法保证事务的持久性,怎么办?
redo log 解决了这个问题 。就是说数据库在修改数据时 , 会把更新记录先写到 redo log 中,再去修改 Buffer Pool 中的数据 , 当提交事务时,调用 fsync 把 redo log 刷入磁盘 。至于缓存中更新的数据文件何时刷入磁盘,则由后台线程异步处理 。
我们先看一下Mysql数据更新的流程:

binlog,redolog,undolog Mysql三种日志的作用和区别

文章插图
下面详细拆解一下图中容易产生疑问的几个点:
  1. 首先当用户对数据进行变更操作时 , 在数据真正变更之前,存储引擎层会先将当前数据保存在undolog中形成一个历史版本,以便回滚的时候使用 。
  2. 然后在将脏页刷新到磁盘之前 , 存储引擎层会先将变更数据的记录写入到redo log buffer中,并且通过顺序IO刷新到磁盘当中的redolog中 , 将redolog的状态置为prepare(这里其实就相当于告诉Binlog我已经记录好数据变化了,你可以开始更新了) 。
  3. 于是接下来server层会进行binlog日志文件的更新,将数据变化写入到binlog中,当binlog更新完成后事务才算成功commit,并将commit这个状态写入到redolog中 。
  4. 最后在执行刷脏页这个操作 , 这个刷脏页的操作是随机IO 。
注意:在上述过程中必须要保证redolog和binlog的数据一致性 。
  • 如果redo log写失败了,而binlog写成功了 。那假设内存的数据还没来得及落磁盘,机器就挂掉了 。那主从服务器的数据就不一致了 。(从服务器通过binlog得到最新的数据,而主服务器由于redo log没有记载,没法恢复数据),所以如果redo log写失败了,那我们就认为这次事务有问题,回滚 , 不再写binlog 。
  • 如果redo log写成功了,而binlog写失败了 , 主从将无法同步,所以我们还是会对这次的事务进行回滚操作 , 将无效的binlog给删除(因为binlog会影响从库的数据,所以需要做删除操作)
这也是为什么redolog要分为两个阶段 , 是为了保证redolog和binglo的数据一致性 。
redo log写入策略由innodb_flush_log_at_trx_commit 参数决定 。