Mysql面试题分享十九:Binlog 和redolog 有什么区别?

一、简介

MySQL中有六种日志文件, 分别是:

  • 重做日志(redo log)
  • 回滚日志(undo log)
  • 二进制日志(binlog)
  • 错误日志(errorlog)
  • 慢查询日志(slow query log)
  • 一般查询日志(general log)
  • 中继日志(relay log)

其中重做日志和回滚日志与事务操作息息相关,二进制日志也与事务操作有一定的关系,这三种日志,对理解MySQL中的事务操作有着重要的意义。 这里简单总结一下这三者具有一定相关性的日志。

二、什么是redo log

(重做日志又称为前滚日志)

我们知道 MySQL 数据存在磁盘中,每次读写数据需做磁盘随机IO,并发场景下性能差。为此 MySQL 引入缓存 Buffer Pool 做优化。其包含磁盘中部分数据页(page)的映射,来缓解数据库的磁盘压力。

当从数据库读数据时,首先从缓存中读,缓存中没有,则从磁盘读后放入缓存;当向数据库写数据时,先向缓存中写,此时缓存中的数据页数据会变更,该数据页叫脏页,Buffer Pool 中修改完数据后会按照设定的策略再定期刷到磁盘中去,这个过程叫刷脏页

那么问题来了,如果 Buffer Pool 中修改的数据还没有及时的刷到磁盘,MySQL 宕机重启,就会导致数据丢失,无法保证事务的持久性,怎么办?

redo log 解决了这个问题。就是说数据库在修改数据时,会把更新记录先写到 redo log 中,再去修改 Buffer Pool 中的数据,当提交事务时,调用 fsync 把 redo log 刷入磁盘。至于缓存中更新的数据文件何时刷入磁盘,则由后台线程异步处理。

我们先看一下Mysql数据更新的流程:

下面详细拆解一下图中容易产生疑问的几个点:

  1. 首先当用户对数据进行变更操作时,在数据真正变更之前,存储引擎层会先将当前数据保存在undolog中形成一个历史版本,以便回滚的时候使用。
  2. 然后在将脏页刷新到磁盘之前,存储引擎层会先将变更数据的记录写入到redo log buffer中,并且通过顺序IO刷新到磁盘当中的redolog中,将redolog的状态置为prepare(这里其实就相当于告诉Binlog我已经记录好数据变化了,你可以开始更新了)。
  3. 于是接下来server层会进行binlog日志文件的更新,将数据变化写入到binlog中,当binlog更新完成后事务才算成功commit,并将commit这个状态写入到redolog中。
  4. 最后在执行刷脏页这个操作,这个刷脏页的操作是随机IO

问:上诉过程中为什么redo log file要分为两个状态?

答:是为了保证redolog和binlog的数据一致性。

  • 如果redo log写失败了,而binlog写成功了。那假设内存的数据还没来得及落磁盘,机器就挂掉了。那主从服务器的数据就不一致了。(从服务器通过binlog得到最新的数据,而主服务器由于redo log没有记载,没法恢复数据),所以如果redo log写失败了,那我们就认为这次事务有问题,回滚,不再写binlog。

  • 如果redo log写成功了,而binlog写失败了,主从将无法同步,所以我们还是会对这次的事务进行回滚操作,将无效的binlog给删除(因为binlog会影响从库的数据,所以需要做删除操作)

redo log写入策略

由innodb_flush_log_at_trx_commit 参数决定。

  • innodb_flush_log_at_trx_commit=1,表示在每次事务提交的时候,都把log buffer刷到文件系统中(os buffer)去,并且调用文件系统的“flush”操作将缓存刷新到磁盘上去。这样的话,数据库对IO的要求就非常高了,如果底层的硬件提供的IOPS比较差,那么MySQL数据库的并发很快就会由于硬件IO的问题而无法提升。
  • innodb_flush_log_at_trx_commit=0 ,表示每隔一秒把log buffer刷到文件系统中(os buffer)去,并且调用文件系统的“flush”操作将缓存刷新到磁盘上去。也就是说一秒之前的日志都保存在日志缓冲区,也就是内存上,如果机器宕掉,可能丢失1秒的事务数据。
  • innodb_flush_log_at_trx_commit=2,表示在每次事务提交的时候会把log buffer刷到文件系统中去,但并不会立即刷写到磁盘。如果只是MySQL数据库挂掉了,由于文件系统没有问题,那么对应的事务数据并没有丢失。只有在数据库所在的主机操作系统损坏或者突然掉电的情况下,数据库的事务数据可能丢失1秒之类的事务数据。这样的好处,减少了事务数据丢失的概率,而对底层硬件的IO要求也没有那么高(log buffer写到文件系统中,一般只是从log buffer的内存转移的文件系统的内存缓存中,对底层IO没有压力)。

    image

SOL语句:select @@innodb_flush_log_at_trx_commit;

redo log 的写入方式?

redo log 采用大小固定,循环写入的方式,当写满后,会重新从头开始循环写,类似一个环状。这样设计原因是 redo log 记录的是数据页上的修改,如果 Buffer Pool 中数据页已经刷到磁盘,这些记录就失效了,新日志会将这些失效的记录覆盖擦除。
注意:redo log 满了,在擦除之前,要确保这些要被擦除记录都已经刷到磁盘中了。在擦除旧记录释放新空间期间,不能再接收新的更新请求,此时 MySQL 性能会下降。因此高并发情况下,合理调整 redo log 大小很重要。

crash-safe 能力是什么?

Innodb 引擎有 crash-safe 能力,即事务提交过程中任何阶段,MySQL 宕机重启后都能保证事务的完整性,已提交的数据不会丢失。这种能力是通过redo log保证的,MySQL 宕机重启,系统将自动检查 redo log,将修改还未写入磁盘的数据从 redo log 恢复到 MySQL 中。

三、什么是binlog

binlog 是作为mysql操作记录归档的日志,这个日志记录了所有对数据库的数据、表结构、索引等等变更的操作。也就是说只要是对数据库有变更的操作都会记录到binlog里面来, 可以把数据库的数据当成我们银行账户里的余额,而binlog就相当于我们银行卡的流水。账户余额只是一个结果,至于这个结果怎么来的,那就必须得看流水了。而同样在mysql里我们就是通过binlog来归档、验证、恢复、同步数据。

binlog 记录内容

binlog应该说是Mysql里最核心的日志, 它记录了除了查询语句(select、show)之外的所有的 DDL 和 DML 语句,也就意味着我们基本上所有对数据库的操作变更都会记录到binlog里面。binlog以事件形式记录,不仅记录了操作的语句,同时还记录了语句所执行的消耗的时间。 binlog 有三种记录格式,分别是ROW、STATEMENT、MIXED。

  1. statement(5.6默认)SBR(statement based replication) :语句模式原封不动的记录当前DML。
  2. ROW(5.7 默认值) RBR(ROW based replication) :记录数据行的变化(用户看不懂,需要工具分析)
  3. mixed(混合)MBR(mixed based replication)模式 :以上两种模式的混合

SBR与RBR模式的对比

  • STATEMENT:可读性较高,日志量少,但是不够严谨
  • ROW :可读性很低,日志量大,足够严谨

四、什么是undo log

uedo log 是也属于引擎层(innodb)的日志,从上面的redo log介绍中我们就已经知道了,redo log 和undo log的核心是为了保证innodb事务机制中的持久性和原子性,事务提交成功由redo log保证数据持久性,而事务可以进行回滚从而保证事务操作原子性则是通过undo log 来保证的。

要对事务数据回滚到历史的数据状态,所以我们也能猜到undo log是保存的是数据的历史版本,通过历史版本让数据在任何时候都可以回滚到某一个事务开始之前的状态。
undo log除了进行事务回滚的日志外还有一个作用,就是为数据库实现MVCC多版本并发控制的功能。

啥是回滚和前滚?

(1)回滚
未提交的事务,即事务未执行 commit。但事务内修改的脏页中,有一部分已刷盘。此时数据库宕机重启,需要回滚来将先前那部分已经刷盘的脏块从磁盘上撤销。
(2)前滚
未完全提交的事务,即事务已经执行 commit,但该事务内修改的脏页中只有一部分数据被刷盘,另一部分还在 buffer pool,此时数据库宕机重启,就要用前滚来将未来得及刷盘的数据从 redo log 中恢复出来并刷盘。

undo log记录内容

在Mysql里数据每次修改前,都首先会把修改之前的数据作为历史保存一份到undo log里面的,数据里面会记录操作该数据的事务ID,然后我们可以通过事务ID来对数据进行回滚。

五、二者的区别

redo log 和 binlog 的区别:

  1. 日志类型与存储引擎:Binlog 是 MySQL 服务器层的日志,对所有存储引擎都通用。而 Redolog 是 InnoDB 存储引擎特有的日志。
  2. 日志内容:Binlog 是一种逻辑日志,记录的是对应的 SQL 语句。而 Redolog 是一种物理日志,记录的是每个数据的具体修改。
  3. 幂等性:Binlog 不具有幂等性,会记录所有影响数据库的操作。而 Redolog 具有幂等性,即多次操作的前后状态是一致的。
  4. 写入时机:在事务提交时,Binlog 会一次性将事务写入内存缓冲区。而 Redolog 是在数据准备修改前将数据写入缓冲区的 Redolog 中,事务提交时,先将 Redolog 写入缓冲区,写入完成后再提交事务。
  5. 文件循环使用:Binlog 在写满或者重启之后,会生成新的 Binlog 文件。而 Redolog 是循环使用的,当数据被写入到磁盘后,日志可以被覆盖。

总的来说,Binlog 用于记录所有修改数据库的操作,而 Redolog 更侧重于记录每个数据的具体修改,并用于数据的恢复。

redo log 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。

可以假设一下,如果不采用这种方式,而是就先写 redo log ,再写 binlog ,会怎样? 如果在写 binlog 时,发生了异常,更新操作已经到 redo log 中了,但是此时 binlog 并没有进行更新,是不是出现了数据不一致?

先写 binlog 再写 redo log 也是一样的道理。所以,在写时,先让 redo log 处于 prepare 状态,等 binlog 写完之后,再让 redo log 处于 commit 状态,这样就保持了逻辑上的一致。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

之乎者也·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值