【Mysql】redo log,undo log 和binlog详解(四)

1.Redo log

(1)Redo log 是什么?

redo log通常是物理日志,记录的是数据页的物理修改,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)

redo log 本质上记录的就是对某个表空间的某个数据页的某个偏移量的地方修改了几个字节的值,它需要记录的其实就是 表空间号+数据页号+偏移量+修改的长度+具体的值

在这里插入图片描述

在这里插入图片描述

(2)Redo log作用是什么?

  • 背景: 在进行数据库修改操作的时候(例如更新),先在内存Buffer Pool里面的页中进行修改操作的,这样会导致页变脏(脏页),然后通过一定的脏页刷盘策略,将脏页随机写入到磁盘,实现数据持久化。

如果出现脏页还没有同步到磁盘,此时数据库宕机,内存Buffer Pool的数据被清空掉,导致了之前修改的数据无法持久化,该如何解决?

在这里插入图片描述

  • 脏页刷盘的时机:
  1. 当需要新的内存页,而内存不够用的时候,就要淘汰一些数据页,空出内存给别的数据页使用。如果淘汰的是“脏页”,就要先将脏页写到磁盘。
  2. MySQL 认为系统“空闲”的时候。
  3. MySQL 正常关闭的情况。这时候,MySQL 会把内存的脏页都 flush 到磁盘上,这样下次MySQL 启动的时候,就可以直接从磁盘上读数据,启动速度会很快。
  • 脏页刷盘的痛点:
    (1)随机刷盘时间太长: 所需要的数据是随机分散在磁盘的不同页的不同扇区中的,那么找到相应的数据需要等到磁臂(寻址作用)旋转到指定的页,然后盘片寻找到对应的扇区,才能找到我们所需要的一块数据(随机IO,读取数据速度较慢)
    (2)脏页刷盘策略不能一定保证数据持久化: 会出现服务宕机,buffer pool的脏页没有同步到此盘,导致数据没有持久化。
  • 脏页刷盘宕机数据丢失解决方案:
    WAL( Write-Ahead Logging): 预写式日志 (WAL) 是一种实现事务日志的标准方法。

WAL 的中心思想是对数据文件的修改,必须是只能发生在这些修改已经记录了日志之后(先写日志,再写磁盘),出现崩溃的情况下, 我们可以用日志来恢复数据库。

在mysql中,如果修改了数据,那么事务提交前,首先会被记录成redo日志写入磁盘,等到事务提交时,再把新数据写入磁盘。出现mysql服务奔溃的情况,可以使用redo log 进行恢复。
在这里插入图片描述
问题: 在事务提交之前,有两种日志binlog 和redo log先写入到磁盘中,为什么需要两种不同的日志?这两种日志分别有什么作用?

  • 1)适用对象不同:
    bin log 是 MySQL 的 Server 层实现的,所有引擎都可以使用
    而 redo log 是 InnoDB 引擎特有的
  • 2)写入内容不同:
    bin log 是逻辑日志,记录的是这个语句的原始逻辑,比如 “给 id = 1 这一行的 age 字段加 1”
    redo log 是物理日志,记录的是 “在某个数据页上做了什么修改”
  • 3)写入方式不同:
    bin log 是可以追加写入的。“追加写” 是指 bin log 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志
    redo log 是循环写的,空间固定会被用完

redo log 只会记录未刷入磁盘的日志,已经刷入磁盘的数据都会从 redo log这个有限大小的日志文件里删除。(根据对比数据页的lsn 和redo log 的lsn,将已经刷入此盘的数据清除掉)

而 bin log 是追加日志,保存的是全量的日志(用来同步信息到从节点)。这就会导致一个问题,那就是没有标志能让 InnoDB 从 bin log 中判断哪些数据已经刷入磁盘了,哪些数据还没有。数据库重启后,直接把 redo log 中的数据都恢复至内存就可以了。(因为刷入磁盘的数据被清除掉了)

问题: 为什么事务提交需要两阶段,为什么要写两次redo log,写一次不行吗?

两阶段提交用来保证主从节点在事务提交时保持数据一致性,redo log 是用来帮助主节点服务奔溃恢复数据的,binlog 是主从节点同步数据的,保证redo log 和bin log 日志数据一致

  • 先写binlog ,再写redo log

当前事务提交后,写binlog 成功,突然发生主节点奔溃,但是binlog 已经同步到从节点,在主节点重启后,由于崩溃之前没有写入redo log,导致不会恢复这条数据。这时候会发现从节点比主节点多了一条数据,出现了主从不一致情况。

  • 先写redo log,再写bin log

当前事务提交后,写redo log 成功,突然发生主节点奔溃,但是binlog 已经同步到从节点,在主节点重启后,利用redo log 进行恢复。这时候会发现主节点比从节点多了一条数据,出现了主从不一致情况。

  • 两阶段提交
    在这里插入图片描述
  1. 写redo log prepare 之前奔溃,此刻redo log 和bin log 数据一致,没有问题
  2. 写 binlog 之前奔溃,此刻redo log 没有提交标志(commit),奔溃恢复的时候,由于redo log没有被标记为commit。于是拿着redo log中的XID去binlog中查找,此时肯定是找不到的,那么执行回滚操作
  3. 写commit 之前奔溃,此刻redo log 没有提交标志(commit),但binlog 写成功了。由redo log中的XID可以找到对应的binlog,这个时候直接提交即可。

奔溃恢复的时候,只要redo log 没有commit 标志(有commit 就提交),就拿着xid 去bin log 查找,找到就提交,找不到就回滚

(3)redo 刷盘

InnoDB存储引擎为redo log的刷盘策略提供了innodb_flush_log_at_trx_commit参数,它支持三种策略

  • 设置为0的时候,表示每次事务提交时不进行刷盘操作,不会写到page cache ,而是由后台线程来刷。
  • 设置为1的时候,表示每次事务提交时都将进行刷盘操作(默认值),这种策略会调用 fsync 强制将 os cache 中的数据刷到磁盘
  • 设置为2的时候,表示每次事务提交时都只把redo log buffer内容写入page cache,如果机器宕机了,而系统缓冲区(page cache)中的数据还没同步到磁盘的话,就会丢失数据

InnoDB存储引擎有一个后台线程,每隔1秒,就会把redo log buffer中的内容写到文件系统缓存(page cache),然后调用fsync刷盘。

在这里插入图片描述

问题: redo log 磁盘文件其实是循环写的(覆盖写),那么哪些redo log 是可以是被覆盖的?是怎么判断出来的?

只要 redo log 对应的脏页已经刷到磁盘了,那这部分 redo log 就没用了,奔溃恢复的时候,数据页磁盘已经有数据了,用不到redo log来恢复

  • LSN (log sequence number): 日志的逻辑序列号,在InnoDB存储引擎中,LSN的值会随着日志的写入而逐渐增大。新的日志LSN等于旧的LSN加上新增日志的大小。

可以使用 SHOW ENGINE INNODB STATUS; 命令查看当前InnoDB存储引擎中的各种LSN值的情况。

---
LOG
---
Log sequence number 294669958009
Log flushed up to   294669958009
Pages flushed up to 294669957358
Last checkpoint at  294669957349
0 pending log flushes, 0 pending chkp writes
21957055 log i/o's done, 1.98 log i/o's/second

log sequence number: 代表当前的重做日志redo log(in buffer)在内存中的LSN
log flushed up to: 代表刷到redo log file on disk中的LSN
pages flushed up to: 代表已经刷到磁盘数据页上的LSN,代表Flush链表尾部最早被修改的那个页面对应的oldest_modification属性值。(这样能最快找到刷入此盘的数据页的LSN)

File Header: 用来记录页的一些头信息,由8个部分组成,固定占用38字节。 关键属性:FIL_PAGE_LSN 该值代表该页最后被修改的日志序列位置LSN(Log Sequence Number)

在这里插入图片描述

last checkpoint at: 代表上一次检查点所在位置的LSN

  • CheckPoint 技术:

目的:

  1. 缩短数据库从crash中恢复的时间
  2. 重做日志redo-log不能无限增长

有了checkpoint技术,当数据库从crash恢复时,数据库不需要重放执行所有的重做日志,因为checkpoint检查点 (小于checkpoint_lsn的值) 前面的脏页面已经安全刷回磁盘了。数据库只需要执行检查点之后的脏页面来进行恢复,从而大大减少了恢复的时间。

2.Undo log

(1)undo log 是什么?

undo log是一种用于撤销回退的日志,在事务没提交之前,MySQL会先记录更新前的数据到 undo log日志文件里面,当事务回滚时或者数据库崩溃时,可以利用 undo log来进行回退。

在这里插入图片描述

undo log 格式:

Update 产生的 undo log 类型为 TRX_UNDO_UPD_EXIST_REC,大致结构如下图所示:

  • start、end: 指向记录开始和结束的位置。
  • undo type: undo log 的类型,TRX_UNDO_UPD_EXIST_REC(update操作) 、TRX_UNDO_INSERT_REC(insert操作)、TRX_UNDO_DEL_MARK_REC(delete操作)。
  • undo no: 在当前事务中 undo log 的编号。
  • table id: 表空间ID。
  • old trx_id: 这个属性会保存记录中的隐藏列trx_id,这个属性在MVCC并发读的时候就会起作用了。
  • old roll_pointer: 这个属性保存记录中的隐藏列roll_pointer,这样就可以通过这个属性找到之前的 undo log。
  • 主键列信息: 这一块就需要记录INSERT这行数据的主键ID信息,或者唯一列信息。
  • 索引列信息: 这部分主要是在第二阶段事务提交后用来真正删除记录的。
  • 更新列信息: 记录更新后的信息

在这里插入图片描述

(2)undo log的作用是什么?

在这里插入图片描述

在MySQL中,undo log日志的作用主要有两个:

  • 提供回滚操作【undo log实现事务的原子性】

在进行数据更新操作的时候,不仅会记录redo log,还会记录undo log,如果因为某些原因导致事务回滚,那么这个时候MySQL就要执行回滚(rollback)操作,利用undo log将数据恢复到事务开始之前的状态

根据行记录上面的DB_ROLL_PTR字段的指针找到对应的undo log日志,还原到上一个版本。

  • 提供多版本控制(MVCC)【undo log实现多版本并发控制MVCC】

多个事务开启的时候,select查询的时候不用加锁,能根据当前事务id去undo log 版本链读取快照数据。

undo log 日志上面也有trx_id 事务版本id,当前事务能通过自己的trx_id和行记录上面的undo log 版本链的trx_id 比对,找到当前事务自己能够读取的版本。

(3)undo log 存储机制(回滚段)

在这里插入图片描述
undo log : 默认是存放在系统表空间中的一个特殊段(segment)中,这个段称为回滚段(Rollback Segment),链表中的页面都是从这个回滚段里边申请的。

每个回滚段中有1024个undo log segment。在MySQL5.5之前,只支持1个rollback segment,也就是只能记录1024个undo操作。在MySQL5.5之后,可以支持128个rollback segment,分别从resg slot0 - resg slot127,每一个resg slot,也就是每一个回滚段,内部由1024个undo segment 组成,即总共可以记录128 * 1024个undo操作

3.Binlog

二进制日志 binlog 用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。使用任何存储引擎的 mysql 数据库都会记录 binlog 日志。在 binlog 中记录的是逻辑日志,也就是 SQL 语句。SQL 语句执行后,binlog 追加到日志文件中。可以设置 binlog 文件大小,超过大小后,自动创建新的文件。

binlog 有三种格式,分别为 STATMENT、ROW 和 MIXED

  • STATMENT:把会修改数据的 sql 语句记录到 binlog 中;是 MySQL 5.7.7 之前的默认格式;
  • ROW:不记录每条 sql 语句的上下文信息,仅记录哪条数据被修改了;是 MySQL 5.7.7之后的默认格式;
  • MIXED:基于 STATMENT 和ROW 两种模式的混合复制,一般使用 STATEMENT 模式,对于无法复制的操作使用 ROW 模式;
show variables like 'log_bin%'

mysql-index.0000XX : 保存着对MySQL更改的逻辑
mysql-index.index : 就是位置索引,后续备份恢复使用

在这里插入图片描述

show binlog events in 'mysql-bin.000049'; #查看指定binlog文件的内容 

在这里插入图片描述

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值