MySQL 架构与内部模块(五)

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情

InnoDB 内存结构和磁盘结构

最新官网架构图。传送门 click me!

image.png

内存结构

内存结构里面主要是 Buffer Pool、Change Buffer、Log Buffer、AHI。

image.png

Buffer Pool

Buffer Pool 缓存的是 page 页面信息。

查看服务器状态,里面有很多跟 Buffer Pool 相关的信息:

SHOW STATUS LIKE '%innodb_buffer_pool%';
复制代码

image.png

这些状态都可以在官网查到详细信息。click me!

Buffer Pool 默认大小是 128M(134217728 字节),可以调整。

查看参数(系统变量):

SHOW VARIABLES like '%innodb_buffer_pool%';
复制代码

(redo)Log Buffer

因为刷脏不是实时的,如果 Buffer Pool 里面的脏页还没有刷入磁盘时,数据库宕机或者重启,这些数据就会丢失。

内存的数据必须要有一个持久化的措施。

为了避免这个问题,InnoDB 把所有对页面的修改操作专门写入一个日志文件。

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

image.png

这个日志文件就是磁盘的 redo log(叫做重做日志),对应于/var/lib/mysql/目录下的 ib_logfile0 和 ib_logfile1,默认 2 个文件,每个 48M。

show variables like 'innodb_log%';
复制代码

image.png

参数 含义
innodb_log_file_size 指定每个文件的大小,默认 48M
innodb_log_files_in_group 指定文件的数量,默认为 2
innodb_log_group_home_dir 指定文件所在路径,相对或绝对。如果不指定,则为 datadir 路径

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

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

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

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

  • redo log 有什么特点?

1、redo log 是 InnoDB 存储引擎实现的,并不是所有存储引擎都有。支持崩溃恢复是 InnoDB 的一个特性。

2、redo log 是物理日志,记录的是“在某个数据页上做了什么修改”。

3、redo log 的大小是固定的,前面的内容会被覆盖,一旦写满,就会触发 buffer pool到磁盘的同步,以便腾出空间记录后面的修改。

redo log 的内容主要是用于崩溃恢复。磁盘的数据文件,数据来自 buffer pool(只有 redo log 写满了,不能再记录更多内存的数据了,才把 buffer pool 刷盘,然后覆盖redo log)。

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

undo log tablespace

dev.mysql.com/doc/refman/… dev.mysql.com/doc/refman/…

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

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

undo log 的数据默认在系统表空间 ibdata1 文件中,因为共享表空间不会自动收缩,也可以单独创建一个 undo 表空间。

show global variables like '%undo%';
复制代码
含义
innodb_undo_directory undo 文件的路径
innodb_undo_log_truncate 设置为 1,即开启在线回收(收缩)undo log 日志文 件
innodb_max_undo_log_size 如果 innodb_undo_log_truncate 设置为 1,超过这个大 小的时候会触发 truncate 回收(收缩)动作,如果 page 大小是 16KB,truncate 后空间缩小到 10M。默认 1073741824 字节=1G
innodb_undo_logs 回滚段的数量, 默认 128,这个参数已经过时
innodb_undo_tablespaces 表空间格式,最大 95,这个参数已经过时

有了这些日志之后,我们来总结一下一个更新操作的流程,这是一个简化的过程。name 原值是 zhangsan。

update user set name = 'wangwu' where id=1;
复制代码

1、事务开始,内存(buffer pool)或磁盘(data file)取到这条数据,返回给 Server的执行器;

2、Server 的执行器修改这一行数据的值为 penyuyan;

3、记录 name=qingshan 到 undo log;

4、记录 name=penyuyan 到 redo log;

5、调用存储引擎接口,在内存(Buffer Pool)中修改 name=penyuyan;

6、事务提交。

内存和磁盘之间,工作着很多后台线程。

  • 后台线程

后台线程的主要作用是负责刷新内存池中的数据和把修改的数据页刷新到磁盘。后台线程分为:master thread,IO thread,purge thread,page cleaner thread。

除了 InnoDB 架构中的日志文件,MySQL 的 Server 层也有一个日志文件,叫做binlog,它可以被所有的存储引擎使用。

Binlog

官网传送门,click me!

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

跟 redo log 不一样,它的文件内容是可以追加的,没有固定大小限制。

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

binlog 的另一个功能就是用来实现主从复制,它的原理就是从服务器读取主服务器的 binlog,然后执行一遍。

image.png

有了这两个日志之后,我们来看一下一条更新语句是怎么执行的(这里省略了undo):

例如一条语句:update teacher set name='张三' where id=1;

image.png 1、先从内存或者磁盘拿到这条数据。

2、把 name 改成张三,然后调用存储引擎的 API 接口,写入这一行数据到内存,同时记录 redo log。这时 redo log 进入 prepare 状态,然后告诉执行器,执行完成了,可以随时提交。

3、执行器收到通知后记录 binlog

4、然后调用存储引擎接口,设置 redo log 为 commit 状态。更新完成。

总结一下这张图片的重点:

1、先记录到内存(buffer pool),再写日志文件。

2、记录 redo log 分为两个阶段(preparecommit)。

3、存储引擎server 分别记录不同的日志。

3、记录 redo记录 binlog

猜你喜欢

转载自juejin.im/post/7135578910741233701