mysql 的 Buffer Pool、redo log、undo log、Binlog

缓冲池 Buffer Pool

首先,对于 InnoDB 存储引擎来说,数据都是放在磁盘上的,存储引擎要操作数据,必须先把磁盘里面的数据加载到内存里面才可以操作

磁盘 I/O 的读写相对于内存的操作来说是很慢的。如果我们需要的数据分散在磁盘的不同的地方,那就意味着会产生很多次的 I/O 操作。

所以,无论是操作系统也好,还是存储引擎也好,都有一个预读取的概念。也就是说,当磁盘上的一块数据被读取的时候,很有可能它附的位置也会马上被读取到,这个就叫做局部性原理

InnoDB 设定了一个存储引擎从磁盘读取数据到内存的最小的单位,叫做。操作系统也有页的概念。操作系统的页大小一般是 4K,而在 InnoDB 里面,这个最小的单位默认是 16KB,它是一个逻辑单位。如果要修改这个值的大小,必须修改源码重新编译安装。

MySQL的记录是以“页”为单位存取的,默认大小16K。也就是说,你要访问磁盘中一个记录,不会只读这个记录,而会把它所在的16K数据一起读入内存

 

操作数据的时候,每次都要从磁盘读取到内存(再返回给 Server),有没有什么办法可以提高效率?

InnoDB 设计了一个内存的缓冲区(Buffer Pool)。读取数据的时候,先判断是不是在这个内存区域里面,如果是,就直接读取,然后操作,不用再次从磁盘加载。如果不是,读取后就写到这个内存的缓冲区。

修改数据的时候,也是先写入到 buffer pool,而不是直接写到磁盘。内存的数据页和磁盘数据不一致的时候,我们把它叫做脏页

 

那脏页什么时候才同步到磁盘呢?

InnoDB 里面有专门的后台线程把 Buffer Pool 的数据写入到磁盘,每隔一段时间就一次性地把多个修改写入磁盘,这个动作就叫做刷脏

 

Buffer Pool 默认大小是 128M,可以调整。 查看参数:

SHOW VARIABLES like '%innodb_buffer_pool%';

 

redo log (重做日志)

因为刷脏不是实时的,如果 Buffer Pool 里面的脏页还没有刷入磁盘时,数据库宕机或者重启,这些数据就会丢失。所以内存的数据必须要有一个持久化的措施。为了避免这个问题,InnoDB 把所有对页的修改操作专门写入一个日志文件。

如果有未同步到磁盘的数据,数据库在启动的时候,会从这个日志文件进行恢复操作(实现 crash-safe)。我们说的事务的 ACID 里面 D(持久性),就是用它来实现的。

这个日志文件就是磁盘的 redo log(叫做重做日志)

 

同样是写磁盘,为什么不直接写到 db file 里面去?为什么先写日志再写磁盘?写日志文件和和写到数据文件有什么区别?

我们先来了解一下随机 I/O顺序 I/O 的概念。

如果我们操作的数据是随机分散在磁盘上不同页的不同扇区中,那么找到相应的数据需要等到磁臂旋转到指定的页,然后盘片寻找到对应的扇区,才能找到我们所需要的一块数据,一次进行此过程直到找完所有数据,这个就是随机 IO,读取数据速度较慢。 

假设我们已经找到了第一块数据,并且其他所需的数据就在这一块数据后边,那么就不需要重新寻址,可以依次拿到我们所需的数据,这个就叫顺序 IO

刷盘是随机 I/O ,而记录日志是顺序 I/O(连续写的),顺序 I/O 效率更高。因此先把修改写入日志文件,在保证了内存数据的安全性的情况下,可以延迟刷盘时机,进而提升系统吞吐。

redo log 位于/var/lib/mysql/目录下的 ib_logfile0ib_logfile1,默认 2 个文件,每个 48M(固定大小的)。

show variables like 'innodb_log%';

 

redo log 有什么特点?

  1. redo log 是 InnoDB 存储引擎实现的,并不是所有存储引擎都有。支持崩溃恢复是 InnoDB 的一个特性
  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”
  3. redo log 的大小是固定的,前面的内容会被覆盖,一旦写满,就会触发 buffer pool到磁盘的同步,以便腾出空间记录后面的修改

 

undo log

除了 redo log 之外,还有一个跟修改有关的日志,叫做 undo log。redo log 和 undolog 与事务密切相关,统称为事务日志

undo log(撤销日志或回滚日志)记录了事务发生之前的数据状态(不包括 select)。如果修改数据时出现异常,可以用 undo log 来实现回滚操作(保持原子性)。

在执行 undo 的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页上操作实现的,属于逻辑格式的日志。

undo log 的数据默认在系统表空间 ibdata1 文件中。

 

redo log 和 undo log 的区别

innodb事务日志包括redo log和undo log。redo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作。

  1. redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
  2. undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录。
  3. undo用于支持事务的隔离性,redo支持持久性

内存和磁盘之间,工作着很多后台线程,主要作用是负责刷新内存池中的数据和把修改的数据页刷新到磁盘。

 

Binlog (归档日志)

MySQL 的 Server 层有一个日志文件,叫做binlog,它可以被所有的存储引擎使用。

binlog 以事件的形式记录了所有的 DDL 和 DML 语句,比如“给 ID=1 这一行的count 字段加 1 ”,因为它记录的是操作而不是数据值,属于逻辑日志

 

binlog 有两个非常重要的作用:1、主从复制,2、数据恢复

主从复制的原理就是从服务器读取主服务器的 binlog,然后执行一遍。

在开启了 binlog 功能的情况下,我们可以把 binlog 导出成 SQL 语句,把所有的操作重放一遍,来实现数据的恢复。

 

redo log 和 binlog 的区别

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

  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。

  3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

  4. binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。

  5. Redolog和binlog都是记录数据的改动,前者是针对数据页,后者是记录修改逻辑(这一行要怎么改)

 

两阶段提交

为什么必须有“两阶段提交”呢?

这是为了让两份日志之间的逻辑一致。

由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是先写完 redo log 再写 binlog,或者采用反过来的顺序。

  • 先写 redo log 后写 binlog

    binlog还没写完就宕机了,会导致binlog中数据缺失,后续如果需要binlog恢复数据,就会恢复的数据不正确。

  • 先写 binlog 后写 redo log

    redo log 还没写完就宕机了,崩溃恢复以后这个事务无效,数据还是原来的值,但是binlog中已经有了,当使用binlog恢复数据的时候,就会导致恢复的数据不正确。

总结:

1: prepare阶段 2: 写binlog 3: commit

当在2之前崩溃时

重启恢复:后发现没有commit,回滚。备份恢复:没有binlog 。一致

当在3之前崩溃

重启恢复:虽没有commit,但满足prepare和binlog完整,所以重启后会自动commit。备份:有binlog. 一致

如果redolog是完整的,(包括了prepare和commit),就直接认为成功,不去判断binlog。 

 

posted @ 2022-08-18 11:26  轨迹320  阅读(290)  评论(0编辑  收藏  举报