当前位置:   article > 正文

MySQL中Buffer pool、Log Buffer和redo、undo日志介绍

MySQL中Buffer pool、Log Buffer和redo、undo日志介绍

Buffer Pool 原理

缓冲池是InnoDB存储引擎中一块连续的内存区域,用于缓存磁盘上的数据页和索引页。由于内存访问速度远快于磁盘访问,因此将经常访问的数据和索引加载到缓冲池中,可以显著提高数据库的读写性能。缓冲池的工作原理主要基于“时间局部性”和“空间局部性”原则,即最近访问过的数据在未来很可能再次被访问,且一个数据项被访问时,与其相邻的数据项也很可能被访问。

MySQL中的内存结构

MySQL中内存结构由多个缓冲区构成主要由Buffer Pool、Change Buffer和Log Buffer,如下图所示
在这里插入图片描述

Buffer Pool

Buffer Pool:缓冲池是主内存中的一个区域(若缓冲池没有数据,则从磁盘加载并缓存),然后再以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度。

Buffer Pool默认大小是128M, 以Page页为单位,Page页默认大小16K,如上图中的每个小方格代表Page页。底层采用链表数据结构管理Page。根据状态,将Page分为三种类型:

  • free page : 空闲page,未被使用
  • clean page:被使用page,数据没有被修改过
  • dirty page:脏页,被使用page,数据被修改过,Page页中数据和磁盘的数据产生了不一致

Change Buffer

Change Buffer :更改缓存区(针对非唯一二级索引),在执行DML(insert、update)语句时,如果这些数据的Page没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更操作存在缓冲区Change Buffer中,在未来数据被读取到Buffer Pool中,再将数据合并到Buffer Pool中,最后将合并后的数据刷新到磁盘中。

change buffer更新流程
在这里插入图片描述
Change Buffer的意义是什么?

与聚集索引不同,二级索引通常是非唯一的,并且以相对随机的顺序插入二级索引,(聚集索引通常是有序插入)。这样随机顺序的插入会导致删除和更新操作可能会影响索引树中不相邻的二级索引页,如果每一次都操作磁盘,会造成大量的磁盘IO。有了Change Buffer之后,我们可以在缓冲池Buffer Pool中进行合并处理,减少磁盘IO。

在进行修改时,如果索引设置唯一性,InnoDB必须要做唯一性校验,因此必须查询磁盘,做一次IO操作。会直接将记录查询到BufferPool中,然后在缓冲池修改,不会在ChangeBuffer操作。

Log Buffer

Log Buffer :日志缓冲区,用来保存要写入到磁盘中的log日志数据(redo log、undo log)默认大小16MB,日志缓冲区的日志会定期刷新到磁盘中。如果需要更新、插入或删除多行的事务,增加日志缓冲区的大小可以节省磁盘IO。
其中两个重要的参数

  • innodb_log_buffer_size:缓冲区大小
  • Innodb_flush_log_at_trx_commit:日志刷新到磁盘的时机

redo和undo日志

事务有4种特性:原子性、一致性、隔离性和持久性。那么事务的四种特性到底是基于什么机制实现呢?

  • 事务的隔离性由 锁机制 实现。
  • 而事务的原子性、一致性和持久性由事务的 redo 日志和undo 日志来保证。

REDO LOG 称为 重做日志 ,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持
久性。

UNDO LOG 称为 回滚日志 ,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。
有的DBA或许会认为 UNDO 是 REDO 的逆过程,其实不然。

redo日志

InnoDB存储是以页为单位来管理存储空间的,在真正访问页面之前,需要把在磁盘上的页缓存到内存中的Buffer Pool之后才可以访问。所有的变更都必须先更新缓冲池中的数据,然后缓冲池中的脏页会以一定的频率被刷入磁盘中(checkpoint机制),通过缓冲池来优化CPU和磁盘之间的鸿沟,这样就可以保证整体的性能。

为什么需要REDO日志

  1. 一方面,缓冲池可以帮助我们消除CPU和磁盘之间的鸿沟,checkpoint机制可以保证数据的最终落盘,然而由于checkpoint 并不是每次变更的时候就触发 的,而是master线程隔一段时间去处理的。所以最坏的情况就是事务提交后,刚写完缓冲池,数据库宕机了,那么这段数据就是丢失的,无法恢复。
  2. 另一方面,事务包含 持久性 的特性,就是说对于一个已经提交的事务,在事务提交后即使系统发生了崩溃,这个事务对数据库中所做的更改也不能丢失。

那么如何保证这个持久性呢?

一个简单的做法 :在事务提交完成之前把该事务所修改的所有页面都刷新到磁盘,但是这个简单粗暴的做法有些问题另一个解决的思路 :我们只是想让已经提交了的事务对数据库中数据所做的修改永久生效,即使后来系统崩溃,在重启后也能把这种修改恢复出来。所以我们其实没有必要在每次事务提交时就把该事务在内存中修改过的全部页面刷新到磁盘,只需要把 修改 了哪些东西 记录一下 就好。

比如,某个事务将系统表空间中 第10号 页面中偏移量为 100 处的那个字节的值 1 改成 2,我们只需要记录一下:将第0号表空间的10号页面的偏移量为100处的值更新为 2 。

redo log 基本概念

  • InnoDB引擎对数据的更新,是先将更新记录写入redo log日志,然后会在系统空闲的时候或者是按照设定的更新策略再将日志中的内容更新到磁盘之中。
    这就是所谓的Write-Ahead Log(预先日志持久化):在持久化一个数据页之前,先将内存中相应的日志页持久化。
  • redo log:被称作重做日志, 包括两部分:一个是内存中的日志缓冲: redo log buffer,另一个是磁盘上的日志文件: redo log file

redo的组成

Redo log可以简单分为以下两个部分:redo log buffer、redo log file

  1. 重做日志的缓冲 (redo log buffer),保存在内存中,是易失的。
    参数设置:innodb_log_buffer_size:
    redo log buffer 大小,默认 16M,最大值是4096M,最小值为1M。
mysql> show variables like '%innodb_log_buffer_size%';
+------------------------+----------+
| Variable_name     | Value  |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. 重做日志文件 (redo log file),保存在硬盘中,是持久的。

redo的整体流程

以一个更新事务为例,redo log 流转过程,如下图所示:

在这里插入图片描述

1步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝
第2步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
第3步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加写的方式
第4步:定期将内存中修改的数据刷新到磁盘中
  • 1
  • 2
  • 3
  • 4

redo log的刷盘策略

redo log的写入并不是直接写入磁盘的,InnoDB引擎会在写redo log的时候先写redo log buffer,之后以 一定的频率 刷入到真正的redo log file 中。这里的一定频率怎么看待呢?这就是我们要说的刷盘策略。
在这里插入图片描述
注意,redo log buffer刷盘到redo log file的过程并不是真正的刷到磁盘中去,只是刷入到 文件系统缓存(OS Buffer)中去(这是现代操作系统为了提高文件写入效率做的一个优化),真正的写入会交给系统自己来决定

innodb_flush_log_at_trx_commit 参数设置

针对这种情况,InnoDB给出 innodb_flush_log_at_trx_commit 参数,该参数控制 commit提交事务
时,如何将 redo log buffer 中的日志刷新到 redo log file 中。

缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统缓冲区( OS Buffer )。因此, redo log buffer 写入 redo logfile 实际上是先写入 OS Buffer,然后再通过系统调用 fsync() 将其刷到 redo log file.

Redo Buffer 持久化到 redo log 的策略,可通过 Innodb_flush_log_at_trx_commit 设置:

参数值含义
0 (延迟写)事务提交时不会将 redo log buffer中日志写入到 os buffer, 而是每秒写入 os buffer并调用 fsync()写入到 redo log file中。 也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。
1 (实时写,实时刷)事务每次提交都会将 redo log buffer中的日志写入 os buffer并 调用 fsync()刷到 redo log file中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。
2 (实时写, 延时刷)每次提交都仅写入到 os buffer,然后是每秒调用 fsync()os buffer中的日志写入到 redo log file

在这里插入图片描述
一般建议选择取值2,因为 MySQL 挂了数据没有损失,整个服务器挂了才会损失1秒的事务提交数据

undo 日志

undo log 基本概念

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

  • Undo Log产生和销毁:Undo Log在事务开始前产生;事务在提交时,并不会立刻删除undo log,innodb会将该事务对应的undo log放入到删除列表中,后面会通过后台线程purge thread进行回收处理。

注意: undo log也会产生redo log,因为undo log也要实现持久性保护。

undo log的作用

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

    在数据修改的时候,不仅记录了redo log,还记录了相对应的undo log,如果因为某些原因导致事务执行失败了,可以借助undo log进行回滚。

    undo log 和 redo log 记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。

  2. 提供多版本控制(MVCC)【undo log实现多版本并发控制(MVCC)
    MVCC,即多版本控制。在MySQL数据库InnoDB存储引擎中,用undo Log来实现多版本并发控制(MVCC)。当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据【快照读】。

总体记录undo日志和redo日志流程如下图:

先找是否有加载对应的BufferPool有就使用没有就加载读取 ----> 写入UndoLog —>操作执行数据 —> 写入RedoLogBuffer内存 ----> 写入RedoLog到磁盘文件
在这里插入图片描述

面试题一、 undo log、redo log、 bin log的作用是什么?

undo log 基本概念

  • undo log是一种用于撤销回退的日志,在数据库事务开始之前,MySQL会先记录更新前的数据到 undo log日志文件里面,当事务回滚时或者数据库崩溃时,可以利用 undo log来进行回退。
  • Undo Log产生和销毁:Undo Log在事务开始前产生;事务在提交时,并不会立刻删除undo log,innodb会将该事务对应的undo log放入到删除列表中,后面会通过后台线程purge thread进行回收处理。

注意: undo log也会产生redo log,因为undo log也要实现持久性保护。

undo log的作用

  1. 提供回滚操作【undo log实现事务的原子性】
    在数据修改的时候,不仅记录了redo log,还记录了相对应的undo log,如果因为某些原因导致事务执行失败了,可以借助undo log进行回滚。
    undo log 和 redo log 记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。
  2. 提供多版本控制(MVCC)【undo log实现多版本并发控制(MVCC)
    MVCC,即多版本控制。在MySQL数据库InnoDB存储引擎中,用undo Log来实现多版本并发控制(MVCC)。当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据【快照读】。

redo log 基本概念

  • InnoDB引擎对数据的更新,是先将更新记录写入redo log日志,然后会在系统空闲的时候或者是按照设定的更新策略再将日志中的内容更新到磁盘之中。这就是所谓的预写式技术(Write Ahead logging)。这种技术可以大大减少IO操作的频率,提升数据刷新的效率。
  • redo log:被称作重做日志, 包括两部分:一个是内存中的日志缓冲: redo log buffer,另一个是磁盘上的日志文件: redo log file

redo log的作用

  • mysql 每执行一条 DML 语句,先将记录写入 redo log buffer 。后续某个时间点再一次性将多个操作记录写到 redo log file 。当故障发生致使内存数据丢失后,InnoDB会在重启时,经过重放 redo,将Page恢复到崩溃之前的状态 通过Redo log可以实现事务的持久性 。

bin log基本概念

  • binlog是一个二进制格式的文件,用于记录用户对数据库更新的SQL语句信息,例如更改数据库表和更改内容的SQL语句都会记录到binlog里,但是不会记录SELECT和SHOW这类操作。
  • binlog在MySQL的Server层实现(引擎共用)
  • binlog为逻辑日志,记录的是一条SQL语句的原始逻辑
    • binlog不限制大小,追加写入,不会覆盖以前的日志.
    • 默认情况下,binlog日志是二进制格式的,不能使用查看文本工具的命令(比如,cat,vi等)查看,而使用mysqlbinlog解析查看。

bin log的作用

  1. 主从复制:在主库中开启Binlog功能,这样主库就可以把Binlog传递给从库,从库拿到Binlog后实现数据恢复达到主从数据一致性。
  2. 数据恢复:通过mysqlbinlog工具来恢复数据。

面试题二、redo log与bin log的区别?

1)redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。

2)redo log是物理日志,记录的是“在XXX数据页上做了XXX修改”;binlog是逻辑日志,记录的是原始逻辑,其记录是对应的SQL语句。

  • 物理日志: 记录的是每一个page页中具体存储的值是多少,在这个数据页上做了什么修改. 比如: 某个事物将系统表空间中的第100个页面中偏移量为1000处的那个字节的值1改为2.
  • 逻辑日志: 记录的是每一个page页面中具体数据是怎么变动的,它会记录一个变动的过程或SQL语句的逻辑, 比如: 把一个page页中的一个数据从1改为2,再从2改为3,逻辑日志就会记录1->2,2->3这个数据变化的过程.
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/291210
推荐阅读
相关标签
  

闽ICP备14008679号