为什么MySQL里有binlog和redolog?你知道他们的作用嘛

搞懂MySQL的redolog、binlog

为什么要redolog?

对于一般的理解而言,当更新数据的时候,把数据写入到磁盘就好了,为什么MySQL要先写入redolog并更新内存,在空闲的时候才再把redolog里的数据写入磁盘呢?这里涉及到MySQL里经常说到的WAL(Write-Ahead Logging)技术,也就是先写日志,因为写日志是追加操作,只需要在磁盘上追加一条日志即可,而如果是直接将数据写入磁盘,那么我们需要先找到原先数据存放在磁盘上的地址,然后再写入。显然直接写日志效率更高,redolog有点像是磁盘的缓存,先把要写入的数据放到redolog里,当系统空闲或是redolog写满了的时候,再把redolog写入磁盘。

redolog的特性

  • redolog是InnoDB引擎才有的。
  • redolog的大小是有限的,且是一个循环结构,有一个write_pos和一个checkpoint,当write_pos追上checkpoint的时候,表示redolog写满了,这时MySQL必须将redolog里的内容存储到磁盘以给redolog腾出空间。
  • redolog里写的是物理日志,所谓物理日志指的是里面记录的是磁盘数据页上面的变化。
  • redolog是保证MySQL crash-safe的重要因素。在MySQL崩溃后的恢复,主要靠的就是redolog和binlog来对MySQL进行恢复的,保证数据的完整和一致。

为什么要binlog?

binlog是MySQL恢复数据以及做备份库的重要依据。例如当我们想把数据恢复到今天8点整的状态,这时候就要依赖binlog了,具体的操作流程是:

  1. 先建立备份库
  2. 读取MySQL的快照,如果我们每天0点做一次备份的话,那么就读取今天0点的快照,把备份库的数据先恢复到今天0点的状态。
  3. 然后我们读取binlog里从今天0点到8点的日志,执行日志里的逻辑操作。
  4. 最后用备份库替换掉原库的数据。
    这样就能将数据恢复到今天8点的状态了。
    做备份库的逻辑也是相似的,先读取一个最近的快照,在这个快照的基础上,读取binlog。

binlog的特性

  • binlog是MySQL Server层的,因此不论什么引擎都可以使用binlog。
  • binlog的大小理论上是没有限制的(只要磁盘足够大),因为binlog就是一直追加写逻辑操作日志,当文件太大了,就换一个文件接着写。
  • binlog存储的是逻辑日志,也就是平常我们执行的MySQL的语句。

重要的两阶段提交

当我们更新数据时,两阶段提交的具体流程:

  • 更新操作先写入redolog,这时候这条log的状态是prepared状态
  • 再将逻辑日志写入binlog
  • 最后在binlog写好之后,把redolog里的这条日志的状态改为commit

为什么要两阶段提交?

我们试想一下,假设没有两阶段提交,我们先写redolog再写binlog,或者是先写binlog再写redolog,会发生什么?
update tab set v=v+1 where id=1为例(假设v之前的值为0)

  • 先写redolog,再写binlog:如果在写完redolog之后MySQL崩溃,这时候binlog还没有写,在MySQL恢复的时候,就会出现MySQL里v的值已经是1了,而binlog里并没有update这条语句,这样如果我们要做数据备份,在备份的数据库里v的值就还是0,这样会导致数据的不一致。
  • 先写binlog,再写redolog:如果在写完binlog之后,MySQL崩溃,这时候redolog还没有写,这样在MySQL恢复后,就会出现MySQL里v的值还是0,可是binlog里有这条更新的log,也就意味着当我们做备份库的时候,备份库里的v会是1,导致数据不一致。

那么两阶段提交又为什么能保证数据的一致性呢?
我们也对一些极端情况做一下分析:

  • 假设写完redolog prepared之后,MySQL崩溃,这时候binlog没有写入,当MySQL恢复的时候,发现redolog里有一条prepared的记录,可是binlog里并没有相关的日志,这时候MySQL会丢弃这条prepared日志,也就是说当这条语句并没有执行成功,最终MySQL里v还是0,而binlog里也每有这条更新的日志。
  • 假设写完binlog之后,在把redolog改为commit之前,MySQL崩溃,当MySQL恢复的时候,发现redolog里有prepared的日志,若prepared事务在从Binlog中得到的提交事务列表中,则在InnoDB层提交此事务,也就是说MySQL识别到这条prepared的redolog是有效的,这样通过引擎查询到的v值会是1,同时binlog里也有此事务的日志。
    正是这样两阶段提交保证了数据的一致性。

两阶段提交在跨系统维持数据逻辑一致性时是很常用的方案,对于平常工作中处理到类似问题时具有启发性。例如假设我们的数据库是MySQL+redis来构建的,存在一种需求是我们写了MySQL之后,要去写redis,同时我们希望这两个操作具有一致性,也就是说我们希望他们要么都成功了,要么都失败了,不要在MySQL里写成功了,而在redis里写失败了,最终造成数据不一致。这种情况我们就可以考虑借鉴两阶段提交这个机制。

你可能感兴趣的:(为什么MySQL里有binlog和redolog?你知道他们的作用嘛)