bin log,redo log以及undo log详解

1 bin log

1.1 定义

bin log应该说是Mysql里最核心的日志,是MySQL数据库级别的文件,记录对MySQL数据库各种引擎下执行修改的所有操作(包括DDL和DML语句),不会记录select和show语句,主要用于恢复数据库和同步数据库(主从同步)。

1.2 bin log的三种日志格式

binlog 有三种记录格式,分别是ROW、STATEMENT、MIXED。

1、ROW: 基于变更的数据行进行记录,如果一个update语句修改一百行数据,那么这种模式下就会记录100行对应的记录日志。

2、STATEMENT(mysql默认的日志格式):基于SQL语句级别的记录日志,相对于ROW模式,STATEMENT模式下只会记录这个update 的语句。所以此模式下会非常节省日志空间,也避免着大量的IO操作。

3、MIXED: 混合模式,此模式是ROW模式和STATEMENT模式的混合体,一般的语句修改使用statment格式保存binlog,如一些函数的日志;对于statement无法完成主从复制的操作,则采用row格式保存binlog。

这三种模式需要注意的是:使用 row 格式的 binlog 时,在进行数据同步或恢复的时候不一致的问题更容易被发现,因为它是基于数据行记录的。而使用 mixed 或者 statement 格式的 binlog 时,很多事务操作都是基于SQL逻辑记录,我们都知道一个SQL在不同的时间点执行它们产生的数据变化和影响是不一样的,所以这种情况下,数据同步或恢复的时候就容易出现不一致的情况。

1.3 bin log的刷盘时机

binlog 写入策略在进行事务的过程中,首先会把binlog 写入到binlog cache中(因为写入到cache中会比较快,一个事务通常会有多个操作,避免每个操作都直接写磁盘导致性能降低),事务最终提交的时候再吧binlog 写入到磁盘中。当然事务在最终commit的时候binlog是否马上写入到磁盘中是由参数 sync_binlog 配置来决定的。

1、sync_binlog=0 的时候,表示每次提交事务binlog不会马上写入到磁盘,而是先写到page cache,相对于磁盘写入来说写page cache要快得多,不过在Mysql 崩溃的时候会有丢失日志的风险。

2、sync_binlog=1 的时候,表示每次提交事务都会执行 fsync 写入到磁盘(mysql默认的机制);

3、 sync_binlog的值大于1 的时候,表示每次提交事务都 先写到page cach,只有等到积累了N个事务之后才fsync 写入到磁盘,同样在此设置下Mysql 崩溃的时候会有丢失N个事务日志的风险。很显然三种模式下,sync_binlog=1 是强一致的选择,选择0或者N的情况下在极端情况下就会有丢失日志的风险,具体选择什么模式还是得看系统对于一致性的要求。

2 redo log

2.1 定义

redo log是innodb引擎级别,用来记录innodb存储引擎的事务日志,不管事务是否提交都会记录下来,用于数据恢复。当数据库发生故障,innoDB存储引擎会使用redo log恢复到发生故障前的时刻,以此来保证数据的完整性。将参数innodb_flush_log_at_tx_commit设置为1,那么在执行commit时会将redo log同步写到磁盘。

redo log 的设计目标是支持innodb的“事务”的特性,事务ACID特性分别是原子性、一致性、隔离性、持久性, 一致性是事务的最终追求的目标,隔离性、原子性、持久性是达成一致性目标的手段,根据的文章我们已经知道隔离性是通过锁机制来实现的。 而事务的原子性和持久性则是分别通过undo log和redo log 来保障的。

2.2 binlog可以替换redo log用于宕机后的数据恢复吗?

  1. 最核心的一点就是redo log记录的数据变更粒度和binlog的数据变更粒度是不一样的,也正因为这个binlog是没有进行崩溃恢复事务数据的能力的。

  2. 以修改数据为例,binlog 是以表为记录主体,在ROW模式下,binlog保存的表的每行变更记录
    比如update tb_user set age =18 where name =‘赵白’ ,如果这条语句修改了三条记录的话,那么binlog记录就是

UPDATE `db_test`.`tb_user` WHERE @1=5 @2='赵白' @3=91 @4='1543571201' SET  @1=5 @2='赵白' @3=18 @4='1543571201'
UPDATE `db_test`.`tb_user` WHERE @1=6 @2='赵白' @3=91 @4='1543571201' SET  @1=5 @2='赵白' @3=18 @4='1543571201'
UPDATE `db_test`.`tb_user` WHERE @1=7 @2='赵白' @3=91 @4='1543571201' SET  @1=5 @2='赵白' @3=18 @4='1543571201'redo
  1. redo log则是记录着磁盘数据的变更日志,以磁盘的最小单位“页”来进行记录。
    上面的修改语句,在redo log里面记录得可能就是下面的形式。

把表空间10、页号5、偏移量为10处的值更新为18。

把表空间11、页号1、偏移量为2处的值更新为18。

把表空间12、页号2、偏移量为9处的值更新为18。

当我们把数据从内存保存到磁盘的过程中,Mysql是以页为单位进行刷盘的,这里的页并不是磁盘的页,而是Mysql自己的单位,Mysql里的一页数据单位为16K,所以在刷盘的过程中需要把数据刷新到磁盘的多个扇区中去。 而把16K数据刷到磁盘的每个扇区里这个过程是无法保证原子性的,也就意味着Mysql把数据从内存刷到磁盘的过程中,如果数据库宕机,那么就可能会造成一步分数据成功,一部分数据失败的结果。而这个时候通过binlog这种级别的日志是无法恢复的,一个update可能更改了多个磁盘区域的数据,如果根据SQL语句回滚,那么势必会让那些已经刷盘成功的数据造成数据不一致。所以这个时候还是得需要通过redo log这种记录到磁盘数据级别的日志进行数据恢复。

  1. 另一个很重要的点就是并不知道 bin log中的sql语句是否执行成功,因为没有事务是否提交成功的状态记录字段

2.3 redo log刷盘时机

  1. redo lo占用的空间是一定的,并不会无线增大(可以通过参数设置),写入的时候是进顺序写的,所以写入的性能比较高。当redo log空间满了之后又会从头开始以循环的方式进行覆盖式的写入。

  2. 在写入redo log的时候也有一个redo log buffer,日志什么时候会刷到磁盘是通过innodb_flush_log_at_trx_commit 参数决定。

    • innodb_flush_log_at_trx_commit=0 ,表示每次事务提交时都只是把 redo log 留在 redo log buffer 中,只有当buffer中存储了多个事务日志才会刷入磁盘中;
    • innodb_flush_log_at_trx_commit=1,表示每次事务提交时都将 redo log 直接持久化到磁盘;
    • innodb_flush_log_at_trx_commit=2,表示每次事务提交时都只是把 redo log 写到 page cache(内核缓冲区)。
  3. 除了上面几种机制外,还有其它两种情况会把redo log buffer中的日志刷到磁盘。

    • 定时处理:有线程会定时(每隔 1 秒)把redo log buffer中的数据刷盘。
    • 根据空间处理:redo log buffer 占用到了一定程度( innodb_log_buffer_size 设置的值一半)占,这个时候也会把redo log buffer中的数据刷盘。

3 undo log

除了记录redo log外,当进行数据修改时还会记录undo log,undo log用于数据的撤回操作,它保留了记录修改前的内容。通过undo log可以实现事务回滚,并且可以根据undo log回溯到某个特定的版本的数据,实现MVCC。

注释:redo log 和 undo log都是属于事务日志

4 bin log和redo log

4.1 有什么区别?

  1. bin log会记录所有日志记录,包括InnoDB、MyISAM等存储引擎的日志;redo log只记录innoDB自身的事务日志。
  2. bin log主要用于数据库的 主从复制 以及数据恢复工作(比如恢复到数据库的某一个历史版本),redo log 主要用于发生故障后,让所有数据恢复到发生故障之前的状态
  3. bin log是逻辑日志,记录的是SQL语句;redo log是物理日志,记录的数据格式是 “在某个数据页上做了什么修改”。
  4. bin log的日志空间是二进制流式的缓冲区,写完一个缓冲区后,不会覆盖之前的内容,而是重开一个缓冲区,继续写入日志;
    而redo log的日志空间大小是固定的,通过循环写入的方式将日志写入磁盘,一旦没有空闲空间,则会采用覆盖的方式,覆盖的之前的内容
  5. bin log只在事务提交前被写入一次磁盘(MySQL 5.7.7之后版本的默认保存方式),一个事务只写一次;而对于redo log,在事务开始时会写入一次磁盘,提交redo log为prepare状态,事务提交后又会写入一次磁盘,提交redo log 为commit状态

4.2 bin log日志恢复和redo log日志恢复的区别

binlog(二进制日志)恢复和redo log(重做日志)恢复是数据库恢复机制中的两个不同方面,它们的主要区别在于目标和内容:

  1. 目标不同

    • binlog恢复的主要目标是用于数据库的逻辑恢复和复制。通过分析binlog中记录的SQL语句,可以还原数据库中的数据和操作,以实现数据恢复、主从复制等目标。binlog是用于逻辑恢复和数据同步的工具。
    • redo log恢复的主要目标是用于数据库的物理恢复。redo log包含了InnoDB存储引擎中发生的物理更改(如页的修改),它的主要作用是在数据库发生崩溃或故障时,确保数据的一致性和完整性,以防止数据损坏。redo log是用于物理恢复的工具。
  2. 内容不同

    • binlog内容:binlog记录的是实际执行的SQL语句,这些语句包括数据的插入、更新、删除,以及数据库结构的变更(DDL语句)。binlog中的内容是逻辑操作的记录。
    • redo log内容:redo log记录的是InnoDB存储引擎所执行的物理更改。这包括数据页的修改,而不是SQL语句本身。redo log中的内容是物理操作的记录。
  3. 使用场景不同

    • binlog的使用场景:binlog主要用于实现数据库的逻辑备份和还原,以及主从复制。它适用于恢复到特定时间点、误操作恢复和数据复制等场景。
    • redo log的使用场景:redo log主要用于数据库的物理恢复。它用于保证在数据库崩溃或发生故障时,数据库可以恢复到崩溃前的状态,以确保数据的一致性和完整性。

总之,binlog和redo log在数据库中扮演着不同的角色。binlog主要用于逻辑恢复和复制,记录的是SQL语句的逻辑操作。而redo log主要用于物理恢复,记录的是InnoDB存储引擎的物理操作,以确保数据的一致性和持久性。这两者在数据库备份、恢复和复制方面起到了关键作用,但它们的内容和目标不同。

4.3 这里的逻辑恢复是什么意思?

逻辑恢复(Logical Recovery)是数据库恢复过程中的一种方法,它指的是通过重新执行数据库中的逻辑操作(例如SQL语句)来还原数据,而不是直接依赖于物理备份或重做日志(redo log)的物理恢复。逻辑恢复的目标是使数据库回到一个一致和可用的状态。

在逻辑恢复中,通常使用数据库的事务日志(例如MySQL中的binlog)来重放之前执行的SQL语句。这些日志文件中包含了对数据库进行的各种更改操作,包括数据的插入、更新、删除以及数据库结构的变更。通过分析和逐个执行这些记录的操作,可以还原数据库到特定的时间点或事件前的状态。

逻辑恢复的一些常见用例包括:

  1. 误删除数据的恢复:如果某个用户或管理员不小心删除了重要的数据,可以使用逻辑恢复来还原被删除的数据。

  2. 数据回滚:在某些情况下,需要将数据库还原到之前的状态,以消除错误或回退到先前的版本。

  3. 数据迁移和复制:在数据库迁移或数据复制过程中,可以使用逻辑恢复来将数据从一个数据库实例复制到另一个数据库实例。

逻辑恢复的主要优势在于它提供了更大的灵活性,因为它不仅可以用于数据库的物理恢复,还可以用于数据库的逻辑操作。但与物理恢复相比,逻辑恢复可能会更慢,因为需要逐个执行SQL语句,特别是在大型数据库中。逻辑恢复通常在需要精确恢复特定数据或执行特定操作时使用。

4.4

5 redo log 和 undo log的区别

  1. 目的不同:redo log主要是用于发生故障时的数据恢复操作,将数据恢复到故障发生前的状态,而undo log主要用于事务的回滚**,将数据恢复为事务发生前的状态**

redo log 和 undo log 都是MySQL用于实现事务和保证数据一致性的机制,但它们的作用不同:

  • Redo Log(重做日志): 主要用于保证事务的持久性(Durability)。当事务执行时,首先会把修改记录到redo log中,然后再慢慢地更新到磁盘的数据页中。这样即使系统突然宕机,也可以通过redo log来恢复数据。在MySQL的InnoDB存储引擎中,redo log是固定大小的,采用循环写入的方式,可以保证在系统宕机的情况下,最近的一段时间内的修改都不会丢失。

  • Undo Log(回滚日志): 主要用于实现事务的原子性(Atomicity)和一致性(Consistency)。当事务需要回滚或者其他事务需要读取旧的数据版本时,就需要使用undo log。undo log记录了事务执行过程中对数据的修改,如果事务失败需要回滚,或者其他事务需要读取数据修改前的版本,就会使用undo log中的信息来还原数据。

6 redo、undo、binlog的生成流程与崩溃恢复

当我们执行update user_info set name =“李四” where id=1 的时候大致流程如下:

  1. 从磁盘读取到id=1的记录,放到内存。
  2. 记录undo log 日志。
  3. 记录redo log (预提交状态)
  4. 修改内存中的记录。
  5. 记录binlog
  6. 提交事务,写入redo log (commit状态)

https://pic4.zhimg.com/v2-346d0dcc7b5e7a3295357e099ad54f7b_b.jpg

我们根据上面的流程来看,如果在上面的某一个阶段数据库崩溃,如何恢复数据。

1、在第一步、第二步、第三步执行时据库崩溃:因为这个时候数据还没有发生任何变化,所以没有任何影响,不需要做任何操作。

2、在第四步修改内存中的记录时数据库崩溃:因为此时事务没有commit,所以不管有没有将修改的数据写回磁盘,这里都要进行数据回滚,所以这里会通过undo log进行数据回滚。

3、第五步写入binlog时数据库崩溃:这里和第四步一样的逻辑,此时事务没有commit,所以这里要进行数据回滚,会通过undo log进行数据回滚。

4、执行第六步事务提交时数据库崩溃:如果数据库在这个阶段崩溃,那其实事务还是没有提交成功,但是这里并不能像之前一样对数据进行回滚,因为在提交事务前,binlog可能成功写入磁盘了,所以这里要根据两种情况来做决定。

  • 如果binlog中记录了事务提交的相关信息:那么就"认为"事务已经提交了,这里可以根据redo log对数据进行重做。其实你应该有疑问,其实这个阶段发生崩溃了,最终的事务是没提交成功的,这里应该对数据进行回滚。 这里主要的一个考虑是因为binlog已经成功写入了,而binlog写入后,那么依赖于binlog的其它扩展业务(比如:从库已经同步了日志进行数据的变更)数据就已经产生了,如果这里进行数据回滚,那么势必就会造成主从数据的不一致。

  • 另外一种情况就 是binlog不存在事务记录,那么这种情况事务还未提交成功,所以会对数据进行回滚。

  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值