目录
查看MySQL使用的存储引擎
磁盘文件
系统表空间
用户表空间
InnoDB逻辑存储结构
RedoLog文件
内存结构
缓冲池Buffer Pool
RedoLogBuffer
ChangeBuffer
Double Write
CheckPoint机制下的脏页落盘
RedoLog落盘
查看MySQL使用的存储引擎
```sql
show engines;
```
对于存储引擎的选择,大部分情况下,InnoDB都是正确的选择。除非需要用到某些InnoDB不具备的特性,并且没有其他办法可以替代,否则都应该选择InnoDB引擎。InnoDB存储引擎由 内存池,后台线程 和 磁盘文件三大部分组成。
磁盘文件
InnoDB的主要的磁盘文件主要分为三大块:一是 系统表空间,二是 用户表空间,三是 redo日志文件和归档文件。 二进制文件(binlog)等文件是MySQL Server层维护的文件,所以未列入InnoDB的磁盘文件中。
系统表空间
系统表空间是由一个或者多个数据文件组成。
默认情况下,一个初始大小为10MB,名为ibdata1的系统数据文件在MySQL的data目录下被创 建。
系统表空间包含 InnoDB数据字典(元数据以及相关对象)、double write buffer、change buffer、undo logs的存储区域。 系统表空间也默认包含任何用户在系统表空间创建的表数据和索引数据。
undo log表空间可以通过参数设置,从系统表空间单独移出去
-- 对系统表空间文件数量和大小的设置
SHOW VARIABLES LIKE 'innodb_data_file_path';
用户表空间
如果设置了参数innodb_file_per_table,则用户可以为每个表产生一个独立的用户表空间。
用户表空间的命名规则为:表名.ibd
-- 用户独立表空间开启配置
SHOW VARIABLES LIKE 'innodb_file_per_table';
通过这种方式,用户不用将所有数据都存放于默认的系统表空间中。
用户表空间只存储该表的 数据、索引 信息,其余信息还是存放在默认的系统表空间中。
InnoDB逻辑存储结构
InnoDB存储引擎逻辑存储结构可分为五级:表空间、段、区、页、行。
表空间是由各个段组成的,常见的段有数据段、索引段、回滚段等。
- 一个段会包含多个区
- 一个区由64个连续的页组成,一个区的大小=1M=64个页(16K)。页是 InnoDB管理磁盘的最小单位,也是InnoDB中磁盘和内存交互的最小单位。
-- 叶大小的配置
show global variables like 'innodb_page_size';
- 操作系统管理磁盘的最小单位也是页,是操作系统读写磁盘最小单位,Linux中页一般是4K,可以通 过命令查看。
root@VM-0-14-ubuntu:/var/lib/mysql# getconf PAGE_SIZE
4096
所以InnoDB从磁盘中读取一个数据页时,操作系统会分4次从磁盘文件中读取数据到内存。写入也是 一样的,需要分4次从内存写入到磁盘中。
- 1个页中包含多个行。在MySQL5.7中,InnoDB提供了4种行格 式:Compact、Redundant、Dynamic和Compressed行格式,Dynamic为MySQL5.7默认的行格式。
-- 查看表tuser数据行的格式
SHOW TABLE STATUS LIKE 'tuser';
RedoLog文件
当InnoDB的数据存储文件发生错误时,重做日志文件就能派上用场。InnoDB存储引擎可以使用重 做日志文件将数据恢复为正确状态,以此来保证数据的正确性和完整性。
每个InnoDB存储引擎至少 有1个重做日志文件组(group),每个文件组下至少有2个重做日志文件,如默 认的 ib_logfile0 和 ib_logfile1。 在日志组中每个重做日志文件的大小一致,并以循环写入的方式运行。 InnoDB存储引擎先写入重做日志文件1,当文件被写满时,会切换到重做日志文件2,再当重做日 志文件2也被写满时,再切换到重做日志文件1。
-- 重做日志文件的大小
SHOW VARIABLES LIKE 'innodb_log_file_size';
-- 重做日志文件的数量
SHOW VARIABLES LIKE 'innodb_log_files_in_group';
内存结构
缓冲池Buffer Pool
缓冲池中缓存的数据页类型有:索引页、数据页、undo页、插入缓冲(insert buffer)、 自适应哈希索引(adaptive hash index)、InnoDB存储的锁信息(lock info)和数据字典信息(data dictionary)。
-- 缓冲池大小
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
- InnoDB存储引擎工作时,需要以Page页为最小单位将磁盘中的数据加载到内存中
- 数据字典信息内容 包括表结构、数据库名或表名、字段的数据类型、视图、索引、表字段信息、存储过程、触发器等内 容。当InnoDB打开一张表,就增加一个对应的对象(库对象、表对象等的元信息)到数据字典。
- 额外内存池是InnoDB存储引擎用来存放数据字典信息以及一些内部数据结构的内存空间。一个MySQL Instance中的数据库对象非常多的时候,是需要适当调整该参数的大小以 确保所有数据都能存放在内存中提高访问效率
-- 额外内存池
SHOW VARIABLES LIKE 'innodb_additional_mem_pool_size';
RedoLogBuffer
InnoDB在缓冲池中变更数据时,会首先将相关变更写入重做日志缓冲中,然后再按 时或者当事务提交时写入磁盘(RedoLog落盘机制),这符合Force-log-at-commit原则; 当重做日志写入磁盘后,缓冲池中的变更数据才会依据checkpoint机制择时写入到磁盘中(脏页落盘机制),这符 合WAL原则。
操作系统的文件系统是带有缓存的,当InnoDB向磁盘写入数据时,有可能只是写入到了文件系统的缓存 中,没有真正的“落袋为安”。
ChangeBuffer
在InnoDB引擎上进行插入操作时,一般需要按照主键顺序进行插入,这样才能获得较高的 插入性能。对于次要索引的插入或者更新操作,先判断插入的非主键索引是否在缓冲池中,若在,则直接插入;若不在,则 先放入到一个Change Buffer中。然后再以一定的频率和情况进行Change Buffer和非聚簇索引页子节点的合并操 作。
Double Write
InnoDB在缓冲池中变更数据时,会首先将相关变更写入重做日志缓冲中,然后再按 时或者当事务提交时写入磁盘RedoLog文件。当缓冲池中的页的版本比磁盘要新时(脏页),数据库需要将新版本的页从缓冲池刷新到磁盘表空间
ChangeBuffer给InnoDB存储引擎带来了性能上的提升,那么Double Write带给InnoDB存储引擎 的是数据页的可靠性
对缓冲池的脏页进行落盘时,并不直接写磁盘,而是
- 通过memcpy函数将脏页先复制到内存中的 double write buffer区域,
- 之后通过double write buffer再分两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免操作系统缓冲写带来的问题。
- 在完成double write页的写入后,再将double wirite buffer中的页写入各个表空间文件中。
CheckPoint机制下的脏页落盘
checkpoint触发时机:
当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁 盘。数据库只需对Checkpoint后的重做日志进行恢复,这样就大大缩短了恢复的时间。
当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行 Checkpoint,将脏页也就是页的新版本刷回磁盘。
当重做日志出现不可用时,因为当前事务数据库系统对重做日志的设计都是循环使用的,并不是让 其无限增大的。重做日志可以被重用的部分是指这些重做日志已经不再需要,当数据库发生宕机 时,数据库恢复操作不需要这部分的重做日志,因此这部分就可以被覆盖重用。如果重做日志还需 要使用,那么必须强制Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。
checkpoint分类:
sharp checkpoint:在关闭数据库的时候,将buffer pool中的脏页全部刷新到磁盘中。
fuzzy checkpoint:数据库正常运行时,在不同的时机,将部分脏页写入磁盘。仅刷新部分脏页到 磁盘,也是为了避免一次刷新全部的脏页造成的性能问题。
- Master Thread Checkpoint: 在Master Thread中,会以每秒或者每10秒一次的频率,将部分脏页从内存中刷新到磁盘,这个过程是 异步的。正常的用户线程对数据的操作不会被阻塞。
- FLUSH_LRU_LIST Checkpoint:buffer pool中的LRU列表要保留一定数量的空闲页面,当这个空间页面数量不足的时候,发生FLUSH_LRU_LIST checkpoint。
-- 空闲页的数量
show variables like 'innodb_lru_scan_depth';
- Async/Sync Flush Checkpoint:发生在重做日志不可用的时候,也就是RedoLog文件将要循环一次,覆盖另一个RedoLog时,将buffer pool中的一部分脏页刷新到磁盘中。
- Dirty Page too much:意味着buffer pool中的脏页过多,执行checkpoint脏页刷入磁盘,保证 buffer pool中有足够的可用页面。
-- 脏页的数量
show variables like 'innodb_max_dirty_pages_pct';
RedoLog落盘
数据更新流程:
- 修改数据时,开启事务。
- 判断数据是否在内存中,如果不在内存中,读取磁盘将数据页读取到缓冲池中。
- 如果在内中就直接修改内存缓冲池中的数据页。就会造成内存中的数据页和磁盘的数据页不一致,形成脏页。
- 修改内存数据页之前,需要写redolog缓存区。
- 如果用户执行commit操作,需要把RedoLog中的内容写入磁盘。
- 如果写redolog成功说明事物提交成功,否则commit失败需要回滚。
RedoLog落盘机制
RedoLogBuffer写入磁盘的时机,由参数 innodb_flush_log_at_trx_commit 控制,默认是 1,表示 事务提交后立即落盘。
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';
0:MySQL每秒一次将数据从log buffer写入日志文件并同时fsync刷新到磁盘中。 每次事务提交时,不会立即把 log buffer 里的数据写入到redo log日志文件的。如果 MySQL崩溃或者服务器宕机,此时内存里的数据会全部丢失,最多会丢失1秒的事务。(定时1s刷一次)
1:每次事务提交时,MySQL将数据将从log buffer写入日志文件并同时fsync刷新到磁盘 中。 该模式为系统默认,MySQL崩溃已经提交的事务不会丢失,要完全符合ACID,必须使用默认设置1。(写一次刷一次)
2:每次事务提交时,MySQL将数据从log buffer写入日志文件,MySQL每秒执行一次fsync 操作将数据同步到磁盘中。( 先写入操作系统文件缓冲区,由操作系统决定刷盘时机 )