MySQL 整体结构和InnoDB 存储设计
1.MySQL 逻辑设计
1.1 Connectors
连接器, 供多种语言与SQL交互
1.2 Connection Pool 连接池
- 管理用户连接, 等待处理连接请求
- 负责监听对MySQL Server的各种请求, 转发所有连接请求到线程管理模块(客户端请求-线程: 1对1)
- 连接线程主要工作就是负责 Server与客户端通信; 线程管理模块负责维护连接线程(创建, 销毁, 缓存)
1.3 Parser 解析器
验证和解析SQL命令, 将SQL语句进行词法分析和语法分析, 解析成 语法树
1.4 Optimizer 查询优化
SQL语句在查询之前会 使用查询优化器对查询进行优化 , Explain查看的SQL语句执行计划就由查询优化器生成
1.5 Cache 和 Buffer 查询缓存
select请求的返回结果集 cache 到内存中, 与该 query 的一个 hash 值 做一个对应.
表缓存, 记录缓存, key缓存, 权限缓存
1.6 存储引擎
可插拔的存储引擎架构, 即如何存储数据, 如何为存储的数据建立索引和如何更新, 查询数据等技术
存储引擎种类
存储引擎 | 说明 |
---|---|
MyISAM | 具有较高查询速度, 但不支持事务 |
InnoDB | 支持事务(XA 协议)和行级锁, 外键 |
Memory | 内存存储引擎, 插入, 更新和查询效率高, 适用于临时表的存储, 面临数据丢失问题 |
Archive | 将数据压缩后进行存储, 非常适合存储大量的独立的, 作为历史记录的数据, 但是只能进行插入和查询操作 |
InnoDB vs MyISAM
InnoDB | MyISAM | |
---|---|---|
存储文件 | .frm: 表定义文件 .ibd: 数据文件和索引文件 | .frm: 表定义文件 .myd: 数据文件 .myi: 索引文件 |
锁 | 行锁, 表锁 | 表锁 |
事务 | 支持 | 不支持 |
适用场景 | 读 写 | 读 |
除非需要用到某些InnoDB不具备的特性, 并且没有其他办法可以替代,否则都应该选择InnoDB引擎
2.MySQL文件结构
MySQL通过文件系统对数据和索引进行存储, 物理结构上可以分为日志文件和索引文件
2.1 日志文件-顺序IO
记录了数据库操作信息和错误信息, 包括 错误日志 , 二进制日志 , 查询日志 , 慢查询日志 , 事务redo日志 , 中继日志
show variables like 'log_%';
(1) 错误日志
记录运行过程中遇到的所有严重的错误信息和MySQL启动和关闭的详情信息, 错误日志所记录的信息是可以通过log-error
和log-warnings
来定义的,其中log-err是定义是否启用错误日志的功能和存储位置, log-warnings是定义是否将警告信息也定义至错误日志中
(2) 二进制日志
binlog
记录了数据库所有的ddl
语句和dml
语句, 但不包括select语句内容, 语句以事件的形式保存, 描述了数据的变更顺序, binlog
还包括了每个更新语句的执行时间信息.
如果是DDL
语句, 则直接记录到binlog日志; 而DML
语句, 必须通过事务提交才能记录到binlog
日志
binlog
主要用于实现 mysql主从复制 、 数据备份 、 数据恢复
插入数据时, 先内存, 再 redo_log
然后 binlog
(两个写入的过程类似于分布式事务)
(3) 通用查询日志
默认是关闭的, 由于通用查询日志会记录用户的所有操作, 其中还包含增删查改等信息, 在并发操作大的环境下会产生大量的信息从而导致不必要的磁盘IO, 会影响mysql的性能的.如若不是为了调试数据库的目的 建议不要开启查询日志
show global variables like 'general_log';
(4) 慢查询日志
记录执行时间超过 long_query_time 秒的所有查询,便于收集查询时间比较长的SQL语句
查询多少SQL超过了慢查询时间的阀值: show global status like '%slow_queries%';
#开启慢查询日志
slow_query_log=ON
#慢查询的阈值
long_query_time=10
#日志记录文件如果没有给出file_name值,
#默认为主机名,后缀为-slow.log。如果给出了文件名,
#但不是绝对路径名,文件则写入数据目录。
slow_query_log_file= file_name
2.2 数据文件-IO
查看MySQL数据文件: show variable like '%datadir%';
(1) InnoDB数据文件
.frm
文件 : 存放表相关的数据信息, 包括表结构的定义信息
.ibd
文件 : 使用 独享表空间 存储 表数据和索引 信息, 一张表对应一个ibd文件
ibdata
文件 : 使用 共享表空间 存储 表数据 和 索引 信息, 所有表共同使用一个或者多个ibdata文件
(2) MyISAM数据文件
.frm
文件 : 存放与表相关的数据信息, 包括表结构的定义信息
.myd
文件 : 存储数据信息
.myi
文件 : 存储表数据文件中任何索引的数据树
3.MySQLServer层对象
3.1 Sql语句执行流程
组件拆解, MySQL 可以分为 Server 层 和 存储引擎层 两部分:
Server 层 包括连接器、查询缓存、分析器、优化器、执行器等, 涵盖 MySQL 的大多数核心服务功能, 以及所有的内置函数(如日期、时间、数学和加密函数等), 所有跨存储引擎的功能都在这一层实现, 比如存储过程、触发器、视图等。
存储引擎层 负责数据的存储和提取.其架构模式是插件式的, 支持 InnoDB、MyISAM、Memory 等多个存储引擎.最常用的存储引擎是 InnoDB.
3.2 连接器
连接完成后, 如果没有后续的动作, 这个连接就处于空闲状态, 可以在 show processlist
命令中看到它. 图中的 Command 列显示为“Sleep”的这一行, 就表示现在系统里面有一个空闲连接
客户端如果太长时间没动静, 连接器就会自动将它断开. 这个时间是由参数 wait_timeout
控制的, 默认值是 8 小时
数据库里面, 长连接 是指连接成功后, 如果客户端持续有请求,则一直使用同一个连接。短连接则是指每次执行完很少的几次查询就断开连接, 下次查询再重新建立一个.
全部使用长连接后, 可能会发现, 有些时候 MySQL 占用内存涨得特别快 , 这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的. 这些资源会在连接断开的时候才释放. 所以如果 长连接累积 下来, 可能导致内存占用太大,被系统强行杀掉 (OOM),从现象看就是 MySQL 异常重启了
解决方式:
1.定期断开长连接. 用一段时间, 或者程序里面判断执行过一个占用内存的大查询后, 断开连接, 之后要查询再重连;
2.可以在每次执行一个比较大的操作后, 通过执行mysql_reset_connection 来重新初始化连接资源;
3.3 查询缓存 MySQL8.0 剔除
获取到查询请求后, 先到查询缓存找找(判断是否之前执行过这条语句), 之前执行过的语句和结果K-V结构缓存在内存中.
查询缓存往往弊大于利 , 查询缓存的失效非常频繁, 只要有对一个表的更新, 这个表上所有的查询缓存都会被清空. 因此很可能
费劲地把结果存起来, 还没使用呢, 就被一个更新全清空了(实际场景, 实际分析)
3.4 分析器
以 MySQL 服务器程序首先需要对这段文本做分析, 判断请求的语法是否正确, 然后从文本中将要查询的表, 列和各种查询条件都提取出来,本质上是对一个SQL语句编译的过程,涉及词法解析、语法分析、语义分析等阶段
3.5 优化器
执行 SQL 语句前, 需要经过优化器处理, 根据解析树生成不同的执行计划, 选择一种最优的执行计划, MySQL 里面使用的是基于成本模型的优化器, 哪种执行计划执行时成本最小就用哪种. 而且它是 io_cost
和 cpu_cost
的开销总和, 评价一个查询的执行效率的一个常用指标: show status like 'Last_query_cost';
哪些方面会遇到优化处理:
1.当有多个索引可用的时候, 决定使用哪个索引;
2.在一个语句有多表关联 (join) 的时候, 决定各个表的连接顺序, 以哪个表为基准表
3.6 执行器
先判断一下对这个表有没有执行查询的权限, 如果有权限, 就使用指定的存储引擎打开表开始查询. 执行器会根据表的引擎定义, 去使用这个引擎提供的查询接口, 提取数据
4.InnoDB存储引擎
4.1 InnoDB整体设计
InnoDB存储引擎由 内存池 , 后台线程 , 磁盘文件三部分组成
4.2 InnoDB 磁盘文件
主要的磁盘文件主要分为三大板块: 系统表空间 , 用户表空间 , redo日志和归档文件
注意 : 二进制文件等文件是 Server层维护的文件
(1) 系统表空间和用户表空间
系统表空间存储哪些数据?
一个共享的表空间, 包括 InnnoDB 数据字典(元数据和相关对象),
double write buffer
,change buffer
、undo logs
的存储区域; 此外, 还包含任何用户在系统表空间创建的 表数据 和 索引数据 。
用户表空间存储哪些数据?
用户表空间只存储该表的数据、索引和插入缓冲BITMAP等信息,其余信息还是存放在默认的系统表空间中。
(2) 重做日志文件
哪些文件是重做日志文件?
默认情况下, 在InnoDB存储引擎的数据目录下会有两个名为 ib_logfile0 和 ib_logfile1 的文件, 这就是InnoDB的重做日志文件 (redo log file) , 它记录了对于InnoDB存储引擎的事务日志。
重做日志文件的作用是什么?
当InnoDB的数据存储文件发生错误时, InnoDB存储引擎可以使用重做日志文件将数据恢复为正确状态, 保证数据的正确性和完整性
为了得到更高的可靠性,用户可以设置多个镜像日志组, 将不同的文件组放在不同的磁盘上,以此来提高重做日志的高可用性。
重做日志文件组是如何写入数据的?
每个InnoDB存储引擎至少有1个重做日志文件组(group), 每个文件组下至少有2个重做日志文件, 如默认的 ib_logfile0 和 ib_logfile1
在日志组中每个重做日志文件的大小一致, 并以 循环写入 的方式运行。
如何设置重做日志文件大小?
用户可以使用
innodb_log_file_size
来设置重做日志文件的大小, 这对InnoDB存储引擎的性能有着非常大的影响。重做日志文件设置的太大, 数据丢失时, 恢复时可能需要很长的时间; 设置的太小, 重做日志文件太小会导致依据
checkpoint
的检查需要频繁刷新脏页到磁盘中, 导致 性能的抖动 。
(3) InnoDB 逻辑存储结构
InnoDB存储引擎逻辑存储结构可分为五级: 表空间、段、区、页、行。
a.表空间
从逻辑存储结构看, 所有数据都被逻辑地存放在一个空间中,称之为表空间(tablespace).
从功能上来看, InnoDB存储引擎的表空间分为系统表空间, 独占表空间, 通用表空间, 临时表空间, Undo表空间.
如果开启了独立表空间
innodb_file_per_table=1
, 每张表的数据都会存储到一个独立的表空间, 即一个单独的.ibd文件. InnoDB 存储引擎有一个共享表空间,叫做系统表空间,对一个磁盘上的文件名为ibdata1. 如果设置了参数
innodb_file_per_table=0
, 关闭了独占表空间,则所有基于InnoDB存储引擎的表数据都会记录到系统表空间.
b.段
表空间是由各个段组成的,常见的段有数据段、索引段、回滚段等。
一个用户表空间里面由很多个段组成,创建一个索引时会创建两个段: 数据段和索引段 。
数据段 存储着索引树中 叶子节点 的data; 索引段 存储着索引树中 非叶子节点 的数据;
一个段的空间大小是随着表的大小自动扩展的:表有多大,段就有多大。
一个段会包含多个区, 至少会有一个区, 段扩展的最小单位是区
c.区
一个区由64个连续的页组成 , 一个区的大小 = 1M = 64个页(16K). 为了保证区中页的连续性, 区扩展时 InnoDB 存储引擎会一次性从磁盘申请4 ~ 5个区
d.页
InnoDB 每个页默认大小时是 16KB, 页是 InnoDB管理磁盘的最小单位, 也InnoDB中磁盘和内存交互的最小单位
show global variables like 'innodb_page_size';
索引树上一个节点就是一个页, MySQL规定一个页上最少存储2个数据项. 如果向一个页插入数据时, 这个页已将满了, 就会从区中分配一个新页. 如果向索引树叶子节点中间的一个页中插入数据, 如果这个页是满的, 就会发生 页分裂
操作系统管理磁盘的最小单位也是页, 是操作系统读写磁盘最小单位, Linux中页一般是4K, 可以通过 getconf PAGE_SIZE
命令查看
所以InnoDB从磁盘中读取一个数据页时, 操作系统会分4次从磁盘文件中读取数据到内存 . 写入也是一样的, 需要分4次从内存写入到磁盘中
e.行
InnoDB的数据是以行为单位存储的, 1个页中包含多个行. 在MySQL5.7中,InnoDB提供了4种行格式:Compact、Redundant、Dynamic和Compressed行格式,Dynamic为MySQL5.7默认的行格式。
InnoDB行格式官网:https://dev.mysql.com/doc/refman/8.0/en/innodb-row-format.html
4.3 InnoDB内存结构
(1) Buffer Pool 缓冲池
概述
InnoDB存储引擎是基于磁盘存储的, 按照页的方式进行管理. 但是由于CPU速度和磁盘速度之间的鸿沟, 基于磁盘的数据库系统通常使用 缓冲池 记录来提高数据库的的整体性能. 缓冲池的大小直接影响着数据库的整体性能, 可以通过配置参数
innodb_buffer_pool_size
来设置。
具体来看,缓冲池中缓存的数据页类型有:索引页、数据页、undo页、插入缓冲(insert buffer)、自适应哈希索引(adaptive hash index)、InnoDB存储的锁信息(lock info)和数据字典信息(data dictionary)。
在架构图上可以看到, InnoDB存储引擎的内存区域除了有缓冲池之外, 还有重做日志缓冲和额外内存池. InnoDB存储引擎首先将重做日志信息先放到这个缓冲区中, 然后按照一定频率将其刷新到重做日志文件中. 重做日志缓冲一般不需要设置的很大, 该值可由配置参数 innodb_log_buffer_size
控制。
数据页和索引页
InnoDB存储引擎工作时, 需要以 Page 页
为最小单位去将磁盘中的数据加载到内存中与数据库相关的所有内容都存储在Page结构里.Page分为几种类型,数据页和索引页就是其中最为重要的两种类型。
插入缓冲(更新缓冲)
目的: 针对次要索引的数据插入存在的问题而设计.
当一张表中存在 次要索引 时, 在插入时, 数据页的存放还是按照主键进行顺序存放, 但是对于次要索引叶节点的插入不再是顺序的了, 这时就需要离散的访问次要索引页, 由于 随机读取 的存在导致插入操作性能下降。设计了 Change Buffer 来进行插入优化。对于次要索引的插入或者更新操作,不是每一次都直接插入到索引页中,而是先判断插入的非主键索引是否在缓冲池中,若在,则直接插入;若不在,则先放入到一个Change Buffer中。看似数据库这个非主键的索引已经插到叶节点,而实际没有,这时存放在另外一个位置。然后再以一定的频率和情况进行Change Buffer和非聚簇索引页子节点的合并操作。这时通常能够将 多个插入合并到一个操作中(批量处理) ,这样就大大提高了对于非聚簇索引的插入性能
自适应哈希索引
InnoDB会根据访问的频率和模式, 为热点页建立哈希索引, 来提高查询效率.
AHI是非常好的优化模式,其设计思想是数据库自优化的(self-tuning),即无需DBA对数据库进行人为调整
通过参数innodb_adaptive_hash_index
来考虑禁用或启动此特性, 默认是开启状态: show variables like 'innodb_adaptive_hash_index';
锁信息
数据库系统使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性
数据字典信息
InnoDB有自己的表缓存, 可以称为表定义缓存或者数据字典(Data Dictionary). 当InnoDB打开一张表, 就增加一个对应的对象到数据字典。
数据字典是对数据库中的数据、库对象、表对象等的元信息的集合。在MySQL中,数据字典信息内容就包括表结构、数据库名或表名、字段的数据类型、视图、索引、表字段信息、存储过程、触发器等内容。MySQL INFORMATION_SCHEMA库提供了对数据局元数据、统计信息、以及有关MySQL server的访问信息(例如:数据库名或表名,字段的数据类型和访问权限等)。该库中保存的信息也可以称为MySQL的数据字典。
(2) 内存数据落盘
整体设计
InnoDB内存缓冲池中的数据page要完成持久化的话,通过两个流程来完成: 一个是脏页落盘;一个是预写redo log日志。
当缓冲池中的页的版本比磁盘要新时, 数据库需要将新版本的页从缓冲池刷新到磁盘. 但是如果每次一个页发送变化,就进行刷新,那么性能开发是非常大的,于是InnoDB采用了Write Ahead Log (WAL) 策略和Force Log at Commit机制实现事务级别下数据的持久性。
WAL 要求数据的变更写入到磁盘前, 首先必须将内存中的日志写入到磁盘;
Force-log-at-commit 要求当一个事务提交时, 所有产生的日志都必须刷新到磁盘上, 数据库可以从日志中恢复数据。
为了确保每次日志都写入到重做日志文件, 在每次将重做日志缓冲写入重做日志后, 必须调用一次
fsync
操作, 将缓冲文件从文件系统缓存中真正写入磁盘。可以通过innodb_flush_log_at_trx_commit
来控制重做日志刷新到磁盘的策略
脏页落盘
在数据库中进行 读取操作 , 将从磁盘中读到的页放在缓冲池中,下次再读相同的页时, 首先判断该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。
对于数据库中页的 修改操作 ,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为 CheckPoint 的机制刷新回磁盘。
重做日志落盘
那Log Buffer什么时候写入到redo log
? Log Buffer写入磁盘的时机, 由参数innodb_flush_log_at_trx_commit
控制, 默认是 1, 表示事务提交后立即落盘.
https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit
show VARIABLES like 'innodb_flush_log_at_trx_commit';
用户程序写入数据到磁盘文件时,需要调用操作系统的接口,操作系统本身是有缓冲区的,之后依赖操作系统机制不时的将缓存中刷新到磁盘文件中。用户程序可以执行fsync操作将操作系统缓冲区的数据刷入到磁盘文件中
0:MySQL每秒一次将数据从log buffer写入日志文件并同时fsync刷新到磁盘中。每次事务提交时,不会立即把 log buffer 里的数据写入到redo log日志文件的。如果MySQL崩溃或者服务器宕机,此时内存里的数据会全部丢失,最多会丢失1秒的事务。
1:每次事务提交时,MySQL将数据将从log buffer写入日志文件并同时fsync刷新到磁盘中。该模式为系统默认,MySQL崩溃已经提交的事务不会丢失,要完全符合ACID,必须使用默认设置1。
2:每次事务提交时,MySQL将数据从log buffer写入日志文件,MySQL每秒执行一次fsync操作将数据同步到磁盘中。每次事务提交时,都会将数据刷新到操作系统缓冲区,可以认为已经持久化磁盘,如果MySQL崩溃已经提交的事务不会丢失。但是如果服务器宕机或者意外断电,操作系统缓存内的数据会丢失,所以最多丢失1秒的事务。
说明 : 由于MySQL执行刷新操作 fsync() 是阻塞的,直到完成后才会返回,写磁盘的速度是很慢的,因此MySQL 的性能会明显地下降
(3) CheckPoint 检查点机制
由来简介
检查点技术目的是解决以下几个问题:
1.缩短数据库的恢复时间;2.缓冲池不够用时, 将脏页刷新到磁盘;3.重做日志不可用时,刷新脏页。
当 数据库发生宕机 时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁盘。数据库只需对Checkpoint后的重做日志进行恢复,这样就大大 缩短了恢复的时间 。
当 缓冲池不够用 时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页也就是页的新版本刷回磁盘。
当 重做日志出现不可用 时,因为当前事务数据库系统对重做日志的设计都是循环使用的,并不是让其无限增大的。重做日志可以被重用的部分是指这些重做日志已经不再需要,当数据库发生宕机时,数据库恢复操作不需要这部分的重做日志,因此这部分就可以被覆盖重用。如果重做日志还需要使用,那么必须强制Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。
对于InnoDB存储引擎而言,是通过LSN(Log Sequence Number)来标记版本的。LSN是8字节的数字,每个页有LSN,重做日志中也有LSN,Checkpoint也有LSN。
show engine innodb status;
Checkpoint分类
在InnoDB存储引擎内部, 有两种Checkpoint, 分别为:Sharp Checkpoint
、Fuzzy Checkpoint
Sharp Checkpoint
: 在关闭数据库的时候, 将buffer pool中的脏页全部刷新到磁盘中
Fuzzy Checkpoint
: 数据库正常运行时, 在不同的时机, 将部分脏页写入磁盘. 仅刷新部分脏页到磁盘, 也是为了避免一次刷新全部的脏页造成的性能问题
Fuzzy Checkpoint
1.Master Thread Checkpoint
在
Master Thread
中,会以每秒或者每10秒一次的频率,将部分脏页从内存中刷新到磁盘,这个过程是异步的。正常的用户线程对数据的操作不会被阻塞 2.FLUSH_LRU_LIST_Checkpoint
FLUSH_LRU_LIST checkpoint是在单独的
page cleaner
线程中执行的。 MySQL对缓存的管理是通过buffer pool中的LRU列表实现的,LRU 空闲列表中要保留一定数量的空闲页面,来保证buffer pool中有足够的空闲页面来相应外界对数据库的请求; 空闲页的数量由innodb_lru_scan_depth参数表来控制的,因此在空闲列表页面数量少于配置的值的时候,会发生checkpoint,剔除部分LRU列表尾端的页面
show variables like 'innodb_lru_scan_depth';
3.Async/Sync Flush Checkpoint
Async/Sync Flush checkpoint是在单独的
page cleaner
线程中执行的。
show variables like 'innodb_log_file_size';
Async/Sync Flush checkpoint 发生在 重做日志不可用 的时候,将buffer pool中的一部分脏页刷新到磁盘中, 在脏页写入磁盘之后, 事务对应的重做日志也就可以释放了.关于
redo_log
文件的的大小, 可以通过innodb_log_file_size
来配置。对于是执行Async Flush checkpoint还是Sync Flush checkpoint
, 由 checkpoint_age 以及async_water_mark
和sync_water_mark
来决定 1.当
checkpoint_age<sync_water_mark
的时候,无需执行Flush checkpoint
。也就说,redolog
剩余空间超过25%的时候,无需执行Async/Sync Flush checkpoint。 2.当
async_water_mark<checkpoint_age<sync_water_mark
的时候,执行Async Flush checkpoint,也就说,redo log
剩余空间不足25%,但是大于10%的时候,执行Async Flushcheckpoint,刷新到满足条件1 3.当
checkpoint_age>sync_water_mark
的时候,执行sync Flush checkpoint。也就说,redolog
剩余空间不足10%的时候,执行Sync Flush checkpoint,刷新到满足条件1. 4.Dirty Page too much Checkpoint
Dirty Page too much Checkpoint是在
Master Thread
线程中每秒一次的频率实现的 Dirty Page too much 意味着buffer pool中的脏页过多, 执行checkpoint脏页刷入磁盘, 保证buffer pool中有足够的可用页面.
Dirty Page 由
innodb_max_dirty_pages_pct
配置,innodb_max_dirty_pages_pct
的默认值是75%
(4) Double Write 双写
如果说Insert Buffer给InnoDB存储引擎带来了性能上的提升, 那么Double Write带给InnoDB存储引擎的是数据页的可靠性
Double Write由两部分组成, 一部分是内存中的 `double write buffer,大小为2MB, 另一部分是物理磁盘上共享表空间连续的128个页, 大小也为2MB
通过 memcpy
函数将脏页先复制到内存中的 double write buffer
区域,之后通过 double write buffer
再分两次, 每次1MB顺序地写入共享表空间的物理磁盘上, 然后马上调用fsync
函数, 同步磁盘, 避免操作系统缓冲写带来的问题, 完成DW后再将 double wirite buffer
中的页写入各个表空间文件中
如果操作系统在将页写入磁盘中发生崩溃, 在恢复过程中, InnoDB存储引擎可以从共享表空间中的double write中找到该页的一个副本, 将其复制到表空间文件中, 再应用重做日志
(5) Redo log Buffer 重做日志缓冲
InnoDB 缓冲池变更数据时, 会先将相关变更写入重做日志缓冲中, 然后按时或事务提交时写入磁盘, 符合 Force-log-at-commit 原则
重做日志写入磁盘后, 缓冲池中的变更数据才会依据checkpoint机制择时写入到磁盘中, 这符合 WAL 原则
InnoDB的 innodb_flush_log_at_trx_commit
属性可以控制每次事务提交时InnoDB的行为
4.4 InnoDB 后台线程
master thread
核心的后台线程, 主要负责将缓冲池中的数据异步刷新到磁盘, 保证数据的一致性, 包括脏页的刷新, 合并Insert Buffer, undo 页的回收.
机制
每1s
- 日志缓冲刷新到磁盘, 即使这个事务还未提交(always), 即使再大的事务commit时都很快
- 合并 Insert Buffer (possible), 合并操作并不是每秒都在发生, InnoDB 会判断当前 1s 内发生的IO此次数是否小于5, 如果是, 则认为当前的IO压力很小, 可以执行合并 Insert Buffer的操作
- 之多刷新100个InnoDB 的缓冲池的脏页到磁盘(possible), 此刷新操作也不是每秒都在操作
每10s
- 刷新100个脏页到磁盘(possible)
- 合并至多5个插入缓冲(always)
- 将日志缓冲刷新到磁盘(always)
- 删除无用的undo页(always)
- 生成一个 checkpoint
purge thread
innodb_purge_threads=4
, 负责回收已经使用并分配的undo页, purge操作默认是由master thread完成的, 为减轻maser thread 的工作, 提升CPU 利用率和提升存储引擎的性能
page cleaner thread
执行脏页的刷新操作
IO thread
show engine innodb status \G;
可以查看一下线程, 线程参数可以通过参数调整
- insert buffer thread: 1
- log IO thread: 1
- read IO thread: 4
- write IO thread: 4
error monitor thread
服务器出错监控线程
lock monitor thread
和锁相关的线程