【划重点】MySQL技术内幕:InnoDB存储引擎
说明
本⽂绝⼤部分内容来源《MySQL技术内幕:InnoDB存储引擎》⼀书,部分图⽚来源⽹络。#我是搬运⼯#
InnoDB 体系结构
后台线程
InnoDB存储引擎是多线程模型,其后台有多个不同的后台线程,负责处理不同的任务。
Master Thread
Master Thread 主要负责将缓存池中的数据异步刷新到磁盘,保证数据的⼀致性,包括脏页的刷新、合并插⼊缓冲(INSERT BUFFER)、UNDO页的回收。
IO Thread
IO Thread 主要负责 Async IO 请求的回调处理,包含 write、read、insert buffer 和 log IO thread。
Purge Thread
Purge Thread 负责回收已经使⽤并分配的 undo 页,减轻 Master Thread 的⼯作。
Page Cleaner Thread
Page Cleaner Thread 作⽤是将之前版本中脏页的刷新操作都放⼊到单独的线程中来完成,减轻 Master Thread 的⼯作及对于⽤户查询线程的阻塞。
内存
缓冲区
⼀块内存区域,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响;读取数据时,⾸先将从磁盘读到的数据存放在缓冲池中,下⼀次读取直接从缓冲池中取。更新数据时,先更显缓冲池的数据,然后通过后台线程定期将有过更新的缓冲数据刷新到磁盘。从⽽减少磁盘IO的读写。
LRU List、Free List 和 Flush List
数据库缓冲池通过 LRU (Last Recent Used) 算法管理,LRU List ⽤来管理已经读取的页,数据库启动时,LRU List 为空列表,没有任何的页。此时页都存放在 Free List 中,当需要从缓冲池中分页时,⾸先从 Free List 中查是否有可⽤的空闲页,若有空闲页则将该页从 Free 列表中删除并能够放⼊到 LRU List 中,否则淘汰 LRU List 中末尾的页。在 LRU List 中的页被修改后,称该页为脏页(dirty page)。脏页存储于 Flush List,表⽰缓冲池中的页与磁盘页不⼀致,等待被调度刷新。脏页同时存在于 Flush List 与 LRU List 中。
重做⽇志缓冲 redo buffer cache
InnoDB 将重做⽇志⾸先写⼊ redo buffer cache,之后通过⼀定频率写⼊到重做⽇志(redo logo)中。redo buffer cache 不需要设置太⼤,重做⽇志缓冲在⼀下情况下被刷⼊到重做⽇志⽂件中:
(1) Master Thread 每⼀秒将重做⽇志缓冲刷到重做⽇志⽂件
(2) 每个事务提交时会将重做⽇志缓冲刷新到重做⽇志⽂件
(3) 当重做⽇志缓冲池剩余空间⼩于50%时,重做⽇志缓冲刷新到重做⽇志
额外的内存池
InnoDB 对内存的管理是通过⼀种称为内存堆的⽅式进⾏的,对⼀些数据结构进⾏内存分配时,需要从额外的内存池中申请,当该区域不够时,会从缓冲池中进⾏申请。
InnoDB 关键特性
插⼊缓冲(insert buffer)
Insert Buffer
对于【⾮聚集索引】的更新或插⼊操作,不是直接插⼊到索引页中,⽽是先判断插⼊的⾮聚集索引页是否在缓冲池中,若在,则直接插⼊,否则先放⼊到⼀个 Insert Buffer 中。再以⼀定频率和情况进⾏ Insert Buffer 和辅助索引页⼦节点的merge操作,合并插⼊操作,提⾼⾮聚集索引的插⼊性能。
Change Buffer
Insert Buffer 的升级,InnoDb 1.0.x 版本开始引⼊,同样适⽤对象为⾮唯⼀的辅助索引。可以对 DML 操作进⾏缓冲:insert、delete、update。
两次写(double write)
double write 带给 InnoDB 存储引擎的是数据页的可靠性。
当数据库发⽣宕机时,可能InnoDB存储引擎正在写⼊某个页到列表中,⽽这个页只写了⼀部分,,⽐如16KB的页,只写了4KB,之后发⽣宕机,此时次出现【部分写失效】(页断裂)的情况,InnoDB 通过 double write 解决出现这种情况时造成的数据丢失并且⽆法恢复的问题。
double write ⼯作流程:脏页刷新时,先拷贝⾄内存的 double write buffer,从缓冲区分两次接⼊磁盘共享表空间红,顺序写,缓冲区中的脏页数据写⼊实际的各个表空间,离散写。
页断裂数据恢复流程:通过页的 checksum,校验 double write 在磁盘中的数据块,通过 double write 缓冲区数据来修复。
⾃适应哈希索引(Adaptive Hash Index)
InnoDB 会监控对表上各索引页的查询。如果观察到建议哈希索引可以带来速度的提升,则建⽴哈希索引,称之为⾃适应哈希索引(AHI)。AHI 是通过缓冲池的 B+ 树构造来的,因此建⽴的速度⾮常快,⽽且不需要对整张表构建哈希索引,InnoDB 会根据访问频率和模式来⾃动创建⾃适应哈希索引,⽆需⼈为设置⼲预。
⾃适应哈希索引只适⽤于等值查询,⽐如 where smsId = 'XXXXXX',不⽀持范围查。
异步 IO(Asynchronous IO)
InnoDB 采⽤异步IO(AIO)的⽅式来处理磁盘操作,进⽽提⾼对磁盘的操作性能。InnoDB 存储引擎中,read ahead ⽅式的读取是通过AIO 完成,脏页的刷新,即磁盘的写⼊操作也是由 AIO 完成。
刷新临接页(Flush Neighbor Page)
当刷新⼀个脏页到磁盘时,InnoDB 会检测该页所在区的所有页,如果是脏页,则⼀起进⾏刷新。通过 AIO 合并多个 IO 写⼊,减少磁盘的IO,但是可能造成将不怎么脏的页的磁盘写⼊,对于 SSD 磁盘,本⾝有着较⾼的 IOPS,则建议关闭该特性,InnoDB 1.2.x 版本提供参数innodb_flush_neighbors,设置为 0 可关闭该特性。⽽对于普通磁盘,建议开启。
Checkpoint 技术
Checkpoint 技术的⽬的是解决以下问题:
缩短数据库的恢复时间
缓冲池不够⽤时,刷新脏页
重做⽇志不可⽤时,刷新脏页
Checkpoint 类型
Sharp Checkpoint:发⽣在数据库关闭时,将所有脏页刷新到磁盘。
Fuzzy Chckpoint:数据库运⾏时使⽤该⽅式进⾏页的刷新,刷新部分脏页进磁盘。
InnoDB 中可能发⽣的 Fuzzy Checkpoint
Master Thread Checkpoint
Master Thread 以每秒或每⼗秒的速度从缓冲池的脏页列表中刷新⼀定⽐例的页到磁盘,异步进⾏,⽤户查询线程不会阻塞。
FLUSH_LRU_LIST Checkpoint
InnoDB 存储引擎需保证差不多 100 个空闲页可⽤,空闲也不⾜时,InnoDB 会将 LRU 列表尾端的页移除,如果尾端页存在脏页,则需要进⾏ Checkpoint。
Async/Sync Flush Checkpoint
重做⽇志不可⽤时进⾏,强制将⼀些页刷新回磁盘,从脏页列表中选取。根据不同的状态使⽤不同的刷新⽅式(同步或异步)。
Dirty Page too much Checkpoint
脏页数量太多,⽐如占据缓冲池⽐例⼤于 75% 时,强制进⾏刷新,⽐例可调。
MySQL ⽂件
参数⽂件
告诉 MySQL 实例启动时在哪⾥可以到数据库⽂件,并且指定某些初始化参数,这些参数定义了某种内存结构的⼤⼩等设置。在默认情况下,MySQL 实例会按照⼀定的顺序在指定的位置进⾏读取,通过以下命令可以寻:
mysql --help | grep myf
MySQL 数据库中的参数分类
动态参数:MySQL 运⾏期间中可以进⾏实时修改
静态参数:MySQL 运⾏期间不可修改,只读
⽇志⽂件
记录了影响 MySQL 数据库的各种类型活动,常见的⽇志⽂件有:
错误⽇志
对 MySQL 的启动、运⾏、关闭过程进⾏记录,可根据错误⽇志定位问题。不仅记录错误信息,同时也记录⼀些告警信息或正确的信息。
# 查看⽇志⽂件存储路径
mysql> show variables like 'log_error';
+---------------+--------------------------------+
| Variable_name | Value |
+---------------+--------------------------------+
| log_error | /data/mysql_data/ |
+---------------+--------------------------------+
慢查询⽇志
帮助查存在问题的 SQL 语句,记录执⾏时间超过某个时间长度的 SQL 语句。
# 查询记录执⾏时间长度(秒)
mysql> show variables like 'long_query_time' \g;
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+
# 慢查询记录开关
mysql> show variables like 'log_slow_queries' \g;
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| log_slow_queries | ON |
+------------------+-------+
慢查询⽇志⽂件可通过 mysqldumpslow 解析结果并查看。
查询⽇志
查询⽇志记录了所有对 MySQL 数据库请求的信息,⽆论这些请求是否得到了正确的执⾏。默认⽂件名为:主机名.log。
⼆进制⽇志
⼆进制⽇志(binary log)记录了对 MySQL 数据库执⾏更改的所有操作,不包含只读操作。⼆进制⽂件主要有以下⼏种作⽤:恢复:某些数据的恢复需要⼆进制⽇志,例如,在⼀个数据库全备⽂件恢复后,⽤户可以通过⼆进制⽇志进⾏ point-in-time 的恢复。
复制:通过复制和执⾏⼆进制⽇志使⼀台远程的 MySQL 数据库与另⼀台 MySQL 数据库进⾏实时同步。
审计:⽤户可以通过⼆进制⽇志中的信息来进⾏审计,判断是否有对数据库进⾏注⼊攻击。
套接字⽂件
在 UNIX 系统下本地连接 MySQL 可以采⽤ UNIX 域套接字⽅式。
# 查看套接字⽂件地址
mysql> show variables like 'socket';
+---------------+-----------------------+
| Variable_name | Value |
+---------------+-----------------------+
| socket | /var/mysql/mysql.sock |
+---------------+-----------------------+
pid ⽂件
在 MySQL 实例启动时,⽣成的进程ID会被写⼊到⼀个⽂件中,即 pid ⽂件。
# 查看 pid ⽂件
mysql> show variables like 'pid_file';
+---------------+--------------------------------+
| Variable_name | Value |
+---------------+--------------------------------+
| pid_file | /data/mysql_data/data/r002.pid |
+---------------+--------------------------------+
表结构定义⽂件
MySQL 数据的存储是根据表进⾏的,每个表都有与之对应的⽂件,是以 frm 为后缀名的⽂件,记录了表的表结构定义。
InnoDB 存储引擎⽂件
InnoDB 存储引擎独有的⽂件,与InnoDB 存储引擎密切相关,包括表空间⽂件、重做⽇志⽂件。
表空间⽂件
InnoDB 采⽤将存储的数据按表空间进⾏存放的设计。默认配置下有⼀个初始化⼤⼩为 10MB 的 ibdata1 ⽂件,可⾃动增长。可以通过参数 innodb_data_file_path 对其进⾏设置。若设置了参数 innodb_file_per_table,则⽤户可以将每个基于 InnoDB 存储引擎的表产⽣⼀个独⽴表空间。独⽴表空间命名规则:表名.ibd
# 查看是否开启独⽴表空间存储
mysql> show variables like 'innodb_file_per_table';mysql文档手机版
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table | ON |
+-----------------------+-------+
需要注意的是,这些单独的表空间⽂件仅存储该表的数据、索引和插⼊缓冲 BITMAP 等信息,其余信息还是存放在默认表空间中。下图显⽰了 InnoDB 存储引擎对于⽂件的存储⽅式:
重做⽇志⽂件
默认情况下,InnoDB 存储引擎的数据⽬录下会有两个名为 ib_logfile0 和 ib_logfile1 的⽂件,即 InnoDB 存储引擎的重做⽇志⽂件(redo log file),记录了对于 InnoDB 存储引擎的事务⽇志。
当实例或介质存储失败时,例如由于主机断电导致实例失败,InnoDB 存储引擎会使⽤重做⽇志恢复到断电前的时刻,⼀次来保证数据的完整性。InnoDB 存储引擎会逐个循环写⽇志⽂件,当前写的⽇志⽂件被写满后,切到下⼀个⽇志⽂件,当下⼀个⽇志⽂件也被写满后,循环写前⼀个⽇志⽂件。⽇志⽂件数量及⼤⼩可配置(innodb_log_files_in_group、innodb_log_file_size)。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论