【数据库】MySQL InnoDB存储引擎详解 - 读书笔记
MySQL InnoDB存储引擎详解 - 读书笔记
- InnoDB 存储引擎概述
- InnoDB 存储引擎的版本
- InnoDB 体系架构
- 内存
- 缓冲池
- LRU List、Free List 和 Flush List
- 重做日志缓冲(redo log buffer)
- 额外的内存池
- 存储结构
- 表空间
- 系统表空间
- 独立表空间
- 通用表空间
- undo表空间
- 临时表空间
- 段
- 区
- 页
- 行
- 后台线程
- Matser Thread
- IO Thread
- Purge Thread
- Page Cleaner Thread
- Checkpoint 技术
- Sharp Checkpoint(尖峰检查点)
- Fuzzy Checkpoint(模糊检查点)
- InnoDB 关键特性
- 插入缓冲(Insert Buffer)
- 两次写(Double Write)
- 自适应哈希索引(Adaptive Hash Index)
- 异步IO(Async IO)
- 刷新邻接页(Flush Neighbor Page)
- 启动、关闭与恢复
- innodb_fast_shutdown
- innodb_force_recovery
- 模拟故障
《MySQL技术内幕 InnoDB存储引擎 第2版》个人读书笔记
电子书本体:https://pan.baidu.com/s/1vlhnEE7OtYs1tK_sEatHuw?pwd=6jv4
提取码:6jv4
MySQL 官方文档:Chapter 17 The InnoDB Storage Engine
InnoDB 存储引擎概述
以下是 InnoDB 存储引擎的特性列表(mysql 8.3):
特性 | 支持 |
---|---|
B-tree 索引 | 是 |
备份/点恢复(在服务器中实现,而不是在存储引擎中) | 是 |
集群数据库支持 | 否 |
聚集索引 | 是 |
压缩数据 | 是 |
数据缓存 | 是 |
加密数据 | 是(在服务器中通过加密函数实现;在 MySQL 5.7 及更高版本中,支持数据静止加密。) |
外键支持 | 是 |
全文搜索索引 | 是(从 MySQL 5.6 开始支持全文索引。) |
地理空间数据类型支持 | 是 |
地理空间索引支持 | 是(从 MySQL 5.7 开始支持地理空间索引。) |
哈希索引 | 否(InnoDB 内部使用哈希索引来实现其自适应哈希索引功能。) |
索引缓存 | 是 |
锁定粒度 | 行级锁定 |
MVCC | 是 |
复制支持(在服务器中实现,而不是在存储引擎中) | 是 |
存储限制 | 64TB |
T 树索引 | 否 |
事务 | 是 |
更新数据字典统计信息 | 是 |
InnoDB 是 MySQL 数据库系统中最常用的存储引擎之一,尤其在事务处理、并发控制及数据可靠性方面表现突出。以下是对 InnoDB 存储引擎的主要特点和功能的概述:
-
事务支持:InnoDB 提供完全的 ACID(原子性、一致性、隔离性、持久性)事务支持,适用于需要高可靠性和数据一致性的应用场景,如银行交易、电子商务等。
-
行级锁定:InnoDB 实现了行级锁定机制,这意味着在执行事务时只锁定受影响的行,而非整个表,这大大提高了并发环境下多用户读写数据的性能。
-
多版本并发控制(MVCC):InnoDB 采用 MVCC 来实现高并发下的读写操作,允许在不阻塞读操作的情况下进行写操作,提升了并发性能,降低了死锁概率。
-
外键约束:支持外键约束,确保数据的一致性和参照完整性,防止非法的数据操作。
-
缓冲池:内存管理中,InnoDB 使用了一个称为缓冲池的内存区域,用于缓存表数据和索引,减少磁盘 I/O 操作,提高数据读写的效率。
-
崩溃恢复:提供完善的崩溃恢复机制,包括 redo 日志(重做日志)和 undo 日志(撤销日志),保证即使在系统崩溃后也能恢复到崩溃前的一致状态。
-
关键特性:
- 插入缓冲(Insert Buffer):优化对非唯一二级索引插入操作的性能。
- 两次写(Double Write):用于保护数据页免受意外宕机造成的数据损坏。
- 自适应哈希索引(Adaptive Hash Index):自动为经常使用的查询创建哈希索引,提高查询速度。
- 异步IO(Async I/O):提高磁盘I/O性能,减少等待时间。
-
存储结构:InnoDB 存储引擎将数据按照页(Page)的方式组织在磁盘上,并且采用B+树作为索引结构,使得数据检索效率相对较高。
-
内存结构:InnoDB 内部有多个内存区域,如redo log buffer、undo logs、buffer pool manager等,用于管理事务、缓存数据以及辅助事务处理过程。
总之,InnoDB 存储引擎因其强大的事务处理能力和高度并发控制,被广泛应用于企业级应用中,尤其适合那些需要复杂事务处理和高度数据一致性的业务场景。随着MySQL的发展,InnoDB 不断改进和优化,已经成为现代MySQL数据库的默认存储引擎。
InnoDB 存储引擎的版本
-
早期版本:最初的InnoDB是由Innobase Oy公司开发的,并在MySQL数据库中作为一个可选的存储引擎引入。
-
集成到MySQL内核:到MySQL 5.1版本时,MySQL数据库开始允许动态加载存储引擎,意味着InnoDB引擎可以独立于MySQL核心版本进行更新升级。
-
默认存储引擎:从MySQL 5.5版本开始,InnoDB成为默认的表存储引擎,取代了以前的MyISAM存储引擎,强调了其在事务处理和并发控制方面的优势。
-
新特性与优化:后续的MySQL 5.6和5.7版本中,InnoDB引擎获得了更多的改进和优化,例如更好的性能、更高效的内存管理、增强的并发控制、在线DDL操作(如在线添加索引)等。
-
MySQL 8.0:在MySQL 8.0及更高版本中,InnoDB继续得到加强,包括但不限于:
- 更快的整数主键查找速度。
- 默认启用持久化统计信息(persistent statistics)。
- 改进的临时表处理。
- 更强的只读事务性能。
- 对窗口函数的支持更好。
随着时间推移,InnoDB存储引擎不断增强了对更大规模数据处理、更高的并发性能以及更多企业级特性的支持。具体的版本细节和新增功能,需查阅对应MySQL版本的官方文档或发布说明。
InnoDB 体系架构
InnoDB 的体系架构设计兼顾了事务处理、并发控制、数据安全和性能优化。以下是 InnoDB 体系架构的主要组成部分:
-
内存结构:
- Buffer Pool (缓冲池):它是 InnoDB 的核心组件之一,用于缓存表的数据页和索引页,减少对磁盘 I/O 的访问次数。缓冲池中的数据页在事务提交时会根据需要刷新到磁盘。
- Change Buffer(变更缓冲区):对于非唯一二级索引的插入操作,如果所在的数据页尚未加载到缓冲池中,InnoDB 会将这部分修改暂存在变更缓冲区中,待后续数据页加载到缓冲池时再合并写入。
- Adaptive Hash Index(自适应哈希索引):InnoDB 会根据查询模式自动生成哈希索引,加快某些查询的性能。
- Log Buffer(日志缓冲区):存储待写入重做日志文件(redo log)的事务日志记录,以确保事务的持久性和崩溃恢复能力。
-
磁盘存储:
- 表空间(Tablespaces):InnoDB 使用表空间作为逻辑上的数据容器,每个表空间可以包含多个数据文件。系统表空间存放全局数据,用户表空间存放用户数据和索引。
- 重做日志文件(Redo Log):记录了对数据的更改操作,以支持事务的持久性和崩溃恢复。
- 回滚段(Undo Logs):用于实现事务的原子性和一致性,存储了事务回滚所需的历史版本数据。
-
线程与并发控制:
- 后台线程:包括 master thread、IO thread(用于处理redo log刷盘)、purge thread(用于清理不再需要的undo日志)等,共同维护数据库的正常运行和数据一致性。
- 行级锁定(Row-level Locking):InnoDB 支持行级锁定,有效减少并发事务之间的冲突,提高并发性能。
- 多版本并发控制(MVCC):InnoDB 通过 MVCC 实现了非锁定读(Read Committed 或 Repeatable Read 隔离级别下),减少了事务之间的阻塞。
-
数据组织结构:
- 页(Page):InnoDB 使用页作为基本的存储单位,每个页通常为16KB,存储表数据和索引。
- B+树索引:InnoDB 表的数据和二级索引都采用 B+树结构组织,保证高效的数据检索和范围查询。
-
外部接口:
- InnoDB 通过与 MySQL Server 的交互接口,响应来自客户端的 SQL 请求,执行事务处理、查询优化和数据检索等功能。
内存
内存结构中有包括缓冲池(innodb_buffer_pool)、重做日志缓冲(redo log_buffer)、额外内存池(innodb_additional_mem_pool_size)
缓冲池
mysql> show variables like '%innodb_buffer_pool%';
+-------------------------------------+----------------+
| Variable_name | Value |
+-------------------------------------+----------------+
| innodb_buffer_pool_chunk_size | 134217728 |
| innodb_buffer_pool_dump_at_shutdown | ON |
| innodb_buffer_pool_dump_now | OFF |
| innodb_buffer_pool_dump_pct | 25 |
| innodb_buffer_pool_filename | ib_buffer_pool |
| innodb_buffer_pool_in_core_file | ON |
| innodb_buffer_pool_instances | 1 |
| innodb_buffer_pool_load_abort | OFF |
| innodb_buffer_pool_load_at_startup | ON |
| innodb_buffer_pool_load_now | OFF |
| innodb_buffer_pool_size | 134217728 |
+-------------------------------------+----------------+
11 rows in set (0.00 sec)
InnoDB内存数据对象:
innodb_buffer_pool
在数据库系统中,CPU与磁盘速度之间存在极大速度差异,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库整体性能。缓冲池是一块内存区域,通过内存速度弥补磁盘速度较慢带来的影响。
数据库读取页操作,首先将从磁盘读到的页存放到缓冲池中,称为将页fix到缓冲池中。下次读取相同页时,首先判断缓冲池中是否有该夜,如果有,则命中,直接读取该页,如果没有,在进行fix的过程。
数据库中页的修改操作,先修改缓冲池中的页,然后再以一定的频率刷到磁盘上。从缓冲池刷回磁盘操作并不是在每次页发生更改后进行,而是通过一种checkPoint机制刷回磁盘。
缓冲池的大小直接影响着数据库的整体性能。InnoDB存储引擎而言,缓冲池的配置通过参数innodb_buffer_pool_size 来设置。
缓冲池中的数据类型有:索引页(index page),数据页(data page),插入缓冲(change buffer),自适应哈希索引(Adaptive hash index),锁信息(lock info),数据字典信息(dictionary cache)
执行 show engine innodb status 显示的不是当前的状态,而是过去某个时间范围内InnoDB存储引擎的状态。如下:Per second averages calculated from the last 33 seconds 代表的信息为过去33秒内的数据库状态。
mysql> show engine innodb status \G;
...
=====================================
2024-03-13 09:17:27 140257528968960 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 33 seconds
...
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 0
Dictionary memory allocated 489041
Buffer pool size 8192
Free buffers 7033
Database pages 1155
Old database pages 446
Modified db pages 0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 1009, created 146, written 202
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 1155, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
...// 观察缓冲池使用状态
mysql> select POOL_ID,POOL_SIZE,FREE_BUFFERS,DATABASE_PAGES from information_schema.INNODB_BUFFER_POOL_STATS \G;
*************************** 1. row ***************************POOL_ID: 0POOL_SIZE: 8192FREE_BUFFERS: 7033
DATABASE_PAGES: 1155
1 row in set (0.00 sec)
LRU List、Free List 和 Flush List
InnoDB存储引擎是怎么对这么大的内存区域进行管理的呢?
LRU(Latest Rcent Used,最近最少使用)算法 ,LRU List 是 InnoDB 缓冲池的核心组件,它是一个双向链表,用于缓存从磁盘读取的页。即最频繁适用的页再LRU列表的前端,而最少适用的页在LRU列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放LRU列表中尾端的页。InnoDB 对传统的LRU算法做了一些优化。
mysql> show variables like 'innodb_old_blocks%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_old_blocks_pct | 37 |
| innodb_old_blocks_time | 1000 |
+------------------------+-------+
innodb_old_blocks_pct:
- 默认值为 37,取值范围是 5 到 95 之间的整数。
- 此参数决定新读取的数据页在首次进入缓冲池时放置的位置。当数据页首次加载到缓冲池时,会被放在 LRU 链表的中间位置(大致为整个链表长度的 3/8 处,即 37% 处)而不是尾部。这样做的目的是为了让经常访问的新读取页有机会在短时间内再次被访问时仍然保留在缓冲池中,而不是很快被淘汰出去。
innodb_old_blocks_time:
- 默认值为 1000,单位是毫秒。
- 当新读取的数据页被插入到 LRU 中间位置(midpoint)后,此参数控制该数据页在被移动到 LRU 尾部(即将面临淘汰的风险)之前需要等待的最短时间。
- 如果在这段时间内数据页又被访问到,那么它就不会移动到 LRU 尾部,继续保留下来,这样有助于缓存热数据并减少磁盘I/O。
这两个参数共同作用,旨在优化 InnoDB 缓冲池的缓存命中率,特别是对于周期性或临时热点数据,能够有效地保持在缓冲池中,提高数据库的整体性能。可以通过调整这两个参数,根据实际工作负载的特性来微调缓存管理策略。
mysql> SET GLOBAL innodb_old_blocks_time=0;
mysql> SET GLOBAL innodb_old_blocks_pct=20;
Free List :
LRU 列表用来管理已经读取的页,但当数据库刚启动时,LRU列表是空的,即没有任何的页。这时页都存放在Free列表中。Free List 是缓冲池中未分配给任何数据页的空闲块列表。当缓冲池中的页不再需要时(比如已被删除或更新),这些页会被移到 Free List 上,等待重新分配给新的数据页使用。
mysql> show engine innodb status \G;
*************************** 1. row ***************************Type: InnoDBName:
Status:
=====================================
2024-03-13 11:37:39 140257528968960 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 7 seconds
...
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 0
Dictionary memory allocated 489041
Buffer pool size 8192
Free buffers 7033
Database pages 1155
Old database pages 446
Modified db pages 0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 1009, created 146, written 202
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 1155, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
...
----------------------------
END OF INNODB MONITOR OUTPUT
============================1 row in set (0.00 sec)
通过命令 show engine innodb status 可以看到:当前 Buffer pool size 共有 8192 个页,即 8192*16K,总共 128MB 的缓冲池。Free buffers 表示当前 Free 列表中页的数量, Database pages 表示 LRU 列表中页的数量。
Free buffers + Database pages 不等于 Buffer pool size,是因为缓冲池的页可能还会分配给其他不需要 LRU 算法维护的部分(自适应哈希索引、Lock信息、Insert Buffer 等页),因此不存在于 LRU列表中。(如图 <2-2:InnoDB内存数据对象> 所示)
Flush List :
Flush List 主要用于跟踪脏页(即已修改但尚未写回磁盘的数据页)。InnoDB 会定期检查并执行后台刷脏任务,将 Flush List 中的脏页刷新到磁盘,以保持数据的一致性和持久性。当缓冲池空间不足时,InnoDB 也会优先考虑将 Flush List 中的脏页写出并释放空间。
重做日志缓冲(redo log buffer)
mysql> SHOW variables like 'innodb_log_buffer_size';
+------------------------+----------+
| Variable_name | Value |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
1 row in set (0.00 sec)
通常情况下,16M 的重做日志缓冲池足以满足绝大部分的应用,因为重做日志在下列三种情况下会将重做日志缓冲中的内容刷新到外部磁盘的重做日志文件中。
- Master Thread 每一秒将重做日志缓冲刷新到重做日志文件;
- 每个事务提交时会将重做日志缓冲刷新到重做日志文件;
- 当重做日志缓冲池剩余空间小于 1/2 时,重做日志缓冲刷新到重做日志文件。
额外的内存池
额外的内存池通常被DBA忽略,他们认为该值并不十分重要,事实恰恰相反,该值同样十分重要。在InnoDB存储引擎中,对内存的管理是通过一种称为内存堆(heap)的方式进行的。在对一些数据结构本身的内存进行分配时,需要从额外的内存池中进行申请,当该区域的内存不够时,会从缓冲池中进行申请。例如,分配了缓冲池(innodbbuffer_pool),但是每个缓冲池中的帧缓冲(frame buffer)还有对应的缓冲控制对象(buffer controlblock),这些对象记录了一些诸如LRU、锁、等待等信息,而这个对象的内存需要从额外内存池中申请。因此,在申请了很大的InnoDB缓冲池时,也应考虑相应地增加这个值。
存储结构
InnoDB 逻辑存储单元主要分为:表空间、段、区、页。层级关系如下图:
表空间
MySQL5.7以后,表空间分为:系统表空间、独立表空间、通用表空间、undo表空间、临时表空间。
系统表空间
系统表空间以 ibdata1 命名,新建一个数据库时,InnoDB 存储引擎会初始化一个名为 ibdata1 的表空间文件,默认情况下,这个文件存储所有表的数据,比如看不到的系统表,此外,还会存储数据字典、双写缓冲区、更新缓冲区和undo log。MySQL 5.6 以后,已经可以通过参数来设置 undo log 的存储位置了,可以独立于 ibdata1 文件进行存储。
如果系统表空间大小不够,可以配置为自动扩展,使用以下参数指定系统表空间的路径、初始化大小、自动扩展策略。数据库默认的自动扩展大小是 64MB,当然还可以通过添加另一个数据文件来增加系统表空间的大小。
mysql> show variables like '%innodb_data_file_path%';
+-----------------------+------------------------+
| Variable_name | Value |
+-----------------------+------------------------+
| innodb_data_file_path | ibdata1:12M:autoextend |
+-----------------------+------------------------+
1 row in set (0.02 sec)mysql> show variables like '%auto%';
+----------------------------------------------+-------+
| Variable_name | Value |
+----------------------------------------------+-------+
| auto_generate_certs | ON |
| auto_increment_increment | 1 |
| auto_increment_offset | 1 |
| autocommit | ON |
| automatic_sp_privileges | ON |
| binlog_expire_logs_auto_purge | ON |
| caching_sha2_password_auto_generate_rsa_keys | ON |
| innodb_autoextend_increment | 64 |
| innodb_autoinc_lock_mode | 2 |
| innodb_stats_auto_recalc | ON |
| sha256_password_auto_generate_rsa_keys | ON |
| sql_auto_is_null | OFF |
+----------------------------------------------+-------+
12 rows in set (0.00 sec)
MySQL 默认 ibdata1 大小是 12MB(Mysql 8),一般不建议使用默认大小,在遇到高并发事务时,会受到很大影响,建议把 ibdata1 的初始数值大小调整为 1GB
独立表空间
除了系统表空间还有独立表空间(File-per-table),每个表的表空间包含单个 InnoDB 表的数据和索引,并存储在文件系统上的单个数据文件中。
MySQL 每创建一个表,就会生成一个独立表空间,是以 table_name.db 命名的。
系统表空间和独立表空间有什么区别?
- 截断或删除独立表空间中创建的表后,磁盘空间将被释放,而截断或删除系统表空间中的表会在系统表空间数据文件中创建空闲空间,此空间只能用于存储 InnoDB 数据,也就是系统表空间在表截断或删除后占用系统空间不会缩小。
- 可以从另一个 MySQL 实例导入独立表空间中的表,而系统表空间不行
- 更多请查看官网…
通用表空间
与系统表空间类似,通用表空间是能够为多个表存储数据的共享表空间。可以根据活跃度来划分表,存放在不同的磁盘上,可以减少 metadata 的存储开销。
undo表空间
undo表空间包含undo log,这是包含有关如何撤消事务对聚集索引记录的最新更改的信息的记录集合。
undo日志默认存储在系统表空间中,但也可以存储在一个或多个undo表空间中。使用undo表空间可以减少任何一个表空间中undo log所需的空间量。undo log 的 I/O 模式也使 undo 空间成为SSD存储的理想选择 。
临时表空间
把临时表的数据从系统表空间中抽离出来,形成独立的表空间参数 innodb_temp_data_file_path ,独立表空间文件名为 ibtmp1,默认大小 12MB
段
表空间是由段组成的,也可以把一个表理解为一个段,通常由数据段、回滚段、索引段等,每个段由 N 个区和 32 个零散的页组成,段空间扩展是以区为单位进行扩展的,通常情况下,创建一个索引的同时会创建两个段,分别为非叶子节点和叶子节点段。
区
区是由连续的页组成的,是物理上连续分配的一段空间,每个区的大小固定是 1MB
页
InnoDB 的最小物理存储单位是页,有数据页回滚页等。一般情况下,一个区由 64 个连续的页组成,页默认大小是 16KB,可以自行调整页的大小。区也就是 64*16KB = 1MB
行
页里又记录着行记录的信息,InnoDB存储引擎是面向列的,也就是数据是按行存储的。行记录格式可以分为四种:Compact,dynamic,redundant,compressed,MySQL5.7 默认使用 dynamic 行记录格式。Compact 是目前使用最多的一种,但默认是 dynamic ,二者有什么不同?
行溢出简单来讲就是需要存储的数据在当前存储页面外,拆分到多个页进行存储。针对大数据类型 text 或者 blob 存储在其字段中的数据,dynamic 实际采用的数据都存放在溢出的页中,而数据页只存前20个字节的指针。在 compact 行格式下,溢出的列只存放 768 个前缀字节,dynamic 这种行格式模式,针对溢出列所在的新页利用率会更高,所以目前生产环境中建议使用 dynamic 行格式存储。
redundant 是最早的行记录格式,相比 compact 消耗更多存储空间,不建议使用。
compressed 是压缩行格式,对数据和索引页进行压缩。但只是针对物理层面的压缩,在内存中是不压缩的,当数据调用到内存中就涉及转换,会有很多无用的CPU消耗,而且效率也低。压缩比例也不高,大概1/2 的比例,压缩会使数据库的TPS下降,很影响线上业务,不建议使用。
后台线程
MySQL中InnoDB存储引擎使用了多个IO线程来优化和管理与磁盘的交互操作,确保数据的高效读写。
-
Master Thread:主线程是InnoDB存储引擎的核心调度者,负责执行多种后台任务,其中包括清理缓冲池中的脏页(通过checkpoint机制)、合并插入缓存(Insert Buffer)、刷新doublewrite buffer、以及定期检查并关闭空闲事务等。尽管主线程不完全等同于传统的IO线程,但它在处理与磁盘相关的I/O活动时起到了关键作用。
-
IO Thread (Read/Write):InnoDB中有多个读写IO线程,它们专门负责从磁盘读取数据页到内存缓冲池或把缓冲池中的脏页刷新回磁盘。这些线程独立运行,并发地处理I/O请求以提高性能。例如,当查询需要访问尚未加载至缓冲池的数据页时,读取IO线程会异步地将所需页面从磁盘读入内存;同样,在需要将脏页刷回到磁盘时,写入IO线程会将脏页从缓冲池写入到磁盘上的数据文件。
-
Doublewrite Buffer IO Thread:在实现doublewrite功能时,有一个特定的IO线程用于执行doublewrite buffer的操作,即在脏页被写入最终位置之前,先将其复制到一个连续的物理区域,以防止部分写入导致的数据损坏问题。这个过程涉及到两次I/O操作,分别由对应的IO线程进行处理。
-
Log Write Thread:除了上述数据页的读写操作外,还有日志写入线程负责将重做日志缓冲区的内容持久化到磁盘上的重做日志文件中。这是一个至关重要的I/O操作,因为它保障了事务的持久性,即使发生系统崩溃也能恢复未完成的事务。
Matser Thread
MySQL InnoDB 存储引擎中的 Master Thread 是一个非常关键的核心后台线程,它负责协调和调度多种重要任务,确保数据库引擎能够有效地执行事务处理、日志管理、内存管理、I/O操作等核心功能。以下是 Master Thread 的主要工作原理和功能的详细解释:
工作原理概述:
-
主循环 (Loop): Master Thread 执行一系列循环,其中最为核心的是主循环。在主循环中,InnoDB 定期执行一系列定时任务,分为每秒操作和每10秒操作两部分。这些操作可能包括检查并刷新脏页(即将缓冲池中的修改同步到磁盘数据文件)、合并插入缓冲、清理无用的 undo 页等。
-
后台循环 (Background Loop): 当数据库处于空闲状态(没有用户链接)或收到停止命令时,Master Thread 可能会进入后台循环,执行一些不需要实时响应的任务,比如后台 IO 操作、清理无效的数据块等。
-
刷新循环 (Flush Loop): 当需要集中处理脏页刷新到磁盘时,Master Thread 会进入刷新循环,确保重做日志不会因满载而导致事务无法继续进行。此时,Master Thread 将尽可能快地将缓冲池中的脏页写回磁盘,以释放重做日志空间。
-
暂停循环 (Suspend Loop): 若数据库长时间保持空闲,且后台及刷新循环中的任务都已完成,Master Thread 将进入暂停循环,挂起自己,直到有新的事件唤醒它。这样设计有助于节省系统资源。
Master Thread 的具体工作内容:
-
重做日志管理: Master Thread 负责定期将重做日志缓冲区的内容刷新到磁盘上的重做日志文件,以确保事务的持久性。
-
脏页刷新: 定时或按需将缓冲池中的脏页写回磁盘,实现数据的持久化,并释放脏页以供新数据使用。
-
合并插入缓冲: 对于非聚集索引的插入和更新操作,若目标索引页不在缓冲池中,InnoDB 会先将改动暂存于插入缓冲,然后 Master Thread 会在适当时候将多个插入操作合并并批量写入磁盘,从而优化随机写操作。
-
系统监控和清理: 监控和调整系统资源使用,如内存碎片整理、死锁检测和处理、undo页的回收等。
-
其它后台任务: 执行一些计划性的后台维护任务,如统计信息收集、表空间检查、redo log文件切换等。
相关参数:
mysql> show variables like '%innodb_io%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_io_capacity | 200 |
| innodb_io_capacity_max | 2000 |
+------------------------+-------+
2 rows in set (0.01 sec)
这两个参数共同决定了InnoDB在正常情况和突发状况下对磁盘I/O资源的使用策略,对于确保数据库性能稳定性和最大化硬件利用率至关重要。在进行调优时,应根据实际环境中的存储设备类型(HDD、SSD或其他高速存储)、硬件IOPS能力、业务负载特点等因素综合考虑和调整这两个参数。
innodb_io_capacity:
- 这个参数指示了InnoDB认为其所在服务器的磁盘I/O子系统的最大吞吐能力,即每秒能处理多少个页的读写操作。默认值通常是较低的(如200或100),可以根据实际硬件性能进行调整。
- 设置该参数会影响到诸如脏页刷新频率、双写缓冲区(doublewrite buffer)的刷新策略等,从而间接影响到事务提交的速度和数据的持久性保证。
- 如果设置得过低,可能导致系统无法充分利用存储设备的实际I/O能力;过高则可能造成过于激进的脏页刷新,使得IO资源消耗尖峰,反而影响整体性能。
innodb_io_capacity_max:
- 这个参数定义了InnoDB在极端情况下可以临时提升IO操作上限到的最大值。
- 它通常设置为
innodb_io_capacity
参数值的倍数,例如可能是它的两倍或者更高。 - 当系统处于高并发写入压力下,并且存储系统有足够的剩余IO能力时,InnoDB可能会临时提高IO操作量以更快地清理脏页,但不会长期维持在这个峰值水平,以免对其他服务造成影响。
mysql> show variables like '%innodb_max_dirty%';
+--------------------------------+-----------+
| Variable_name | Value |
+--------------------------------+-----------+
| innodb_max_dirty_pages_pct | 90.000000 |
| innodb_max_dirty_pages_pct_lwm | 10.000000 |
+--------------------------------+-----------+
2 rows in set (0.02 sec)
innodb_max_dirty_pages_pct
控制脏页总量的绝对上限,而 innodb_max_dirty_pages_pct_lwm
则是一个更加灵活的指标,用于调节脏页刷新的“宽松度”,使系统能够在较低负载时减少不必要的刷脏动作,在较高负载时又能及时响应,防止脏页累积过多。这两者结合使用,旨在实现对数据库性能和数据安全性的平衡管理。
innodb_max_dirty_pages_pct:
- 这个参数设定了InnoDB缓冲池中脏页(尚未写回磁盘的数据页)所占百分比的上限。一旦缓冲池中的脏页数量达到了这个百分比,InnoDB就开始主动发起刷脏操作,将内存中的数据写回到磁盘上的表空间中。
- 默认情况下,这个百分比设定为75%,也就是说,当缓冲池中有75%的页变为脏页时,InnoDB将开始尝试减少脏页的数量以保持在这个阈值以下。
- 该参数的合理设置有助于平衡内存中数据的持久性和写操作的效率,防止在某些情况下由于大量脏页需要同时刷新导致I/O阻塞,进而影响整个数据库的性能。
innodb_max_dirty_pages_pct_lwm:
- 这是“low water mark”的缩写,意为脏页百分比的低水位标记。
- 当缓冲池中的脏页比例低于这个参数设定的值时,InnoDB会相对减少刷脏页的力度,允许脏页比例上升至较高的程度再进行更积极的刷新操作。
- 设置这个参数可以提供一个更为精细化的控制机制,让InnoDB能够更加智能地调整脏页刷新的策略,在满足一定持久性要求的同时尽可能地减少不必要的I/O活动,从而提升系统性能。
mysql> show variables like '%innodb_adaptive%';
+----------------------------------+--------+
| Variable_name | Value |
+----------------------------------+--------+
| innodb_adaptive_flushing | ON |
| innodb_adaptive_flushing_lwm | 10 |
| innodb_adaptive_hash_index | ON |
| innodb_adaptive_hash_index_parts | 8 |
| innodb_adaptive_max_sleep_delay | 150000 |
+----------------------------------+--------+
5 rows in set (0.00 sec)
innodb_adaptive_flushing: 这个参数控制是否启用InnoDB的自适应刷脏(adaptive flushing)特性。当设置为ON时,InnoDB能够动态调整脏页刷新的策略,根据系统当前的工作负载和IO能力来决定何时将内存中的脏页写回磁盘,以优化系统性能和数据安全性。
innodb_adaptive_flushing_lwm: 这个参数是在启用innodb_adaptive_flushing后使用的,表示脏页百分比的低水位线(lower watermark)。当缓冲池中脏页的比例降低到这个值以下时,InnoDB会相应减慢脏页刷新的速率,而在超过这个比例时增加刷新速度。这有助于在不同的工作负载条件下更平滑地管理IO。
innodb_adaptive_hash_index: 此参数控制是否启用InnoDB的自适应哈希索引功能。当启用时,InnoDB会动态地为经常访问的B-tree索引创建哈希索引,以加快点查询的执行速度。不过,如果表结构频繁变化或者哈希冲突率较高,自适应哈希索引可能反而带来额外的开销。
innodb_adaptive_hash_index_parts: 自适应哈希索引的一个扩展选项,指定将自适应哈希索引划分为多少个部分,以支持多核并行处理,提高并发性能。更高的值意味着更多的并行性和潜在的更好的性能,但也可能消耗更多的内存。
innodb_adaptive_max_sleep_delay: 这个参数决定了InnoDB在检查点和其他后台操作之间等待的最长时间(以微秒为单位)。如果系统没有太多活动,InnoDB会休眠一段时间以减少空闲CPU周期的消耗。更大的数值意味着在低负载时InnoDB会等待更长的时间再进行下一个后台操作,这样可以在不影响性能的前提下节省资源。
IO Thread
innodb_read_io_threads
和 innodb_write_io_threads
均默认为4
mysql> show variables like 'innodb_version' \G;
*************************** 1. row ***************************
Variable_name: innodb_versionValue: 8.3.0
1 row in set (0.01 sec)mysql> show variables like '%innodb%thread%' ;
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| innodb_ddl_threads | 4 |
| innodb_log_writer_threads | ON |
| innodb_parallel_read_threads | 4 |
| innodb_purge_threads | 4 |
| innodb_read_io_threads | 4 |
| innodb_thread_concurrency | 0 |
| innodb_thread_sleep_delay | 10000 |
| innodb_write_io_threads | 4 |
+------------------------------+-------+
8 rows in set (0.00 sec)SHOW ENGINE INNODB STATUS/G;
Purge Thread
回收undolog
innodb_purge_threads 默认为4
Page Cleaner Thread
脏页的刷新操作。
Checkpoint 技术
MySQL InnoDB 存储引擎采用了Checkpoint(检查点)技术来实现持久化和数据恢复,它主要负责将缓冲池(Buffer Pool)中的脏页(dirty pages)定期或在特定条件下刷回到磁盘,确保数据库系统的数据一致性以及在崩溃恢复时能尽快重启服务。
Checkpoint(检查点)技术的目的时解决一下几个问题:
- 缩短数据库的恢复时间;
- 缓冲池不够用时,将脏页刷新到磁盘;
- 重做日志不可用时,刷新脏页。
对于 InnoDB存储引擎而言,其是通过 LSN(Log Sequence Number,日志序列号 )来标记版本的。而LSN是8字节的数字,其单位是字节。每个页有LSN,重做日志中也有LSN,Checkpoint 也有 LSN,可以通过命令 SHOW ENGINE INNODB STATUS 来观察;
mysql> SHOW ENGINE INNODB STATUS \G;
...
---
LOG
---
Log sequence number 32749227
Log buffer assigned up to 32749227
Log buffer completed up to 32749227
Log written up to 32749227
Log flushed up to 32749227
Added dirty pages up to 32749227
Pages flushed up to 32749227
Last checkpoint at 32749227
Log minimum file id is 9
Log maximum file id is 9
41 log i/o's done, 0.00 log i/o's/second
...
在 InnoDB 存储引擎中,Checkpoint 发生的时间、条件及脏页的选择等都非常复杂。而Checkpoint 所做的事情无外乎是将缓存池中的脏页刷回磁盘。不同之处在于每次刷新多少页到磁盘,每次从哪里取脏页,以及什么时间触发Checkpoint。在 InnoDB 存储引擎内部 Checkpoint 主要有两种类型:
Sharp Checkpoint(尖峰检查点)
- Sharp Checkpoint 发生在数据库关闭时将所有的脏页都刷新回磁盘,这时默认的工作方式,即参数
innodb_fast_shutdown = 1
- 但是若数据库在运行时也使用 Sharp Checkpoint,那么数据库的可用性就会受到很大的影响。故在InnoDB存储引擎内部使用Fuzzy Checkpoint进行页的刷新,即只刷新一部分脏页,而不是刷新所有的脏页回磁盘。
Fuzzy Checkpoint(模糊检查点)
Fuzzy Checkpoint 是一种在线检查点,它在数据库运行期间周期性发生,不强制刷新所有脏页,而是采用一种更细粒度的方式来平衡磁盘I/O与系统性能。这种检查点可以根据系统负载和预设的策略自动决定何时刷新部分脏页到磁盘,如基于重做日志文件切换、LRU算法淘汰出的脏页、或者每秒刷脏页的数量等条件触发。
在 InnoDB 存储引擎中可能发生如下几种情况的 Fuzzy Checkpoint:
Master Thread Checkpoint
- 描述: Master Thread是InnoDB存储引擎中的一个重要后台线程,它负责定期执行多种后台任务,其中包括Checkpoint。在Master Thread的主循环中,会根据设定的策略周期性地发起Fuzzy Checkpoint。在该Checkpoint过程中,Master Thread会选择性地将一部分缓冲池中的脏页写入磁盘,而不是强制刷新所有脏页。选择的标准可以是基于时间间隔、脏页数量、重做日志文件切换等因素。
- 目的: 通过这种方式,Master Thread可以持续地将脏页的负担分散到整个系统运行期间,减轻在特定时刻的I/O压力,并确保重做日志不至于过快填满,导致事务无法继续。
FLUSH_LRU_LIST Checkpoint
- 描述: 当InnoDB的缓冲池使用LRU(Least Recently Used)算法进行管理时,最久未使用的页可能会被从缓冲池中淘汰出去,以保证有差不多100个空闲页可供使用。如果被淘汰的页是脏页(即已被修改但尚未写回磁盘),则在页被驱逐出缓冲池之前,会触发一个FLUSH_LRU_LIST Checkpoint,这时会把这部分脏页强制刷回磁盘。而从MySQL 5.6 版本开始,这个检查被放在了一个单独的 Page Cleaner 线程中进行,并且用户可以通过参数
innodb_lru_scan_depth
控制 LRU 列表中可用页的数量。 - 目的: 保证即使在LRU替换过程中,也不会丢失任何已经提交事务的修改,并且维护了数据的一致性和完整性。
mysql> show variables like 'innodb_lru_scan_depth';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_lru_scan_depth | 1024 |
+-----------------------+-------+
1 row in set (0.00 sec)
Async/Sync Flush Checkpoint
- 描述: Async/Sync Flush Checkpoint 指的是重做日志文件不可用的情况,这时需要强制将一些脏页刷新回磁盘,而此时脏页是从脏页列表中选取的。若将已经写入到重做日志的 LSN 记为 redo_lsn,将已经刷新回磁盘最新页的 LSN 记为 checkpoint_lsn,则可定义:
checkpoint_age = redo_lsn - checkpoint_lsn
再定义以下的变量:
async_water_mark = 75% * total_redo_log_file_size
sync_water_mark = 90% * total_redo_log_file_size
若每个重做日志文件的大小为 1GB,并且定义了两个重做日志文件,则重做日志文件的总大小为 2GB。那么 async_water_mark=1.5GB sync_water_mark=1.8GB。则:- 当 checkpoint_age<async_water_mark 时,不需要刷新任何脏页到磁盘;
- 当 async_water_mark<checkpoint_age<sync_water_mark 时触发 Async Flush,从 Flush 列表中刷新足够的脏页回磁盘,使得刷新后满足 checkpoint_age<async_water_mark;
- checkpoint_age>sync_water_mark 这种情况一般很少发生,除非设置的重做日志文件太小,并且在进行类似 LOAD DATA 的 BULK INSERT 操作。此时触发 Sync Flush 操作,从 Flush 列表中刷新足够的脏页回磁盘;使得刷新后满足 checkpoint_age<async_water_mark。
- 目的: 可见,Async/Sync Flush Checkpoint 是为了保证重做日志的循环使用的可用性。在 InnoDB 1.2.x 版本之前,Async Flush Checkpoint 会阻塞发现问题的用户查询线程,而 Sync Flush Checkpoint 会阻塞所有的用户查询线程,并且等待脏页刷新完成。从 InnoDB 1.2.x 版本开始——也就是 MySQL 5.6 版本,这部分的刷新操作同样放到了单独的 Page Cleaner Thread 中,故不会阻塞用户查询线程。
Dirty Page too much Checkpoint
-
描述:
如果缓冲池中的脏页数量过多(超过了InnoDB引擎预设的阈值),即使在Async Flush机制下,也可能触发一次Fuzzy Checkpoint,目的是尽快减少缓冲池中积压的脏页数量,以保持重做日志的滚动和数据库的持久性。 -
目的:
避免脏页累积过多导致重做日志不可用,进而引发事务无法提交或数据库不能正常运作的风险。通过适时的Fuzzy Checkpoint,可以确保即使在极端的写密集型负载下,系统也能保持良好的运行状态和数据安全性。
需要注意的是,随着时间推移和技术发展,MySQL/InnoDB的具体实现细节和配置选项可能会有所改变,但上述原则仍然适用于理解Fuzzy Checkpoint的基本原理和应用场景。
-
脏页刷新:Checkpoint 过程中,InnoDB 需要将那些在缓冲池中修改过的页面(即脏页)的数据写回到磁盘上的数据文件,使得数据文件和缓冲池的内容一致。
-
重做日志循环利用:为了防止重做日志无限增长,当重做日志文件达到一定大小或达到预先设定的阈值时,InnoDB 必须通过 Checkpoint 清理旧的事务记录,以便复用日志空间。
-
恢复过程:在数据库启动时,InnoDB 通过最后一个 Checkpoint 记录的信息,找出需要应用哪些 REDO 日志记录来恢复到一致的状态。只需重放 Checkpoint 后的 REDO 日志,即可将数据库带至崩溃前的最新状态。
通过有效的 Checkpoint 策略,InnoDB 能够在保证数据完整性的同时,尽量减少对磁盘 I/O 的压力,提高数据库的整体性能和可靠性。此外,对于大容量的数据库系统来说,合理的 Checkpoint 设置还能显著缩短数据库在异常情况下的恢复时间。
InnoDB 关键特性
InnoDB提供了事务处理、崩溃修复能力和多版本并发控制的事务安全。以下是InnoDB存储引擎的关键特性:
插入缓冲(Insert Buffer)
插入缓冲是一种优化策略,用于提高非唯一索引的插入性能。当向辅助索引插入数据时,如果主键索引页在内存中不可用,InnoDB会将这些插入操作缓存起来,稍后在后台进行批量处理。这可以减少磁盘I/O操作,提高性能。
mysql> show variables like '%innodb_change%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| innodb_change_buffer_max_size | 25 |
| innodb_change_buffering | all |
+-------------------------------+-------+
innodb_change_buffer_max_size :这个参数表示InnoDB更改缓冲的最大使用比例。其值是一个百分比,默认为25%,范围在0到100之间。更改缓冲主要应用于非唯一二级索引的插入、删除和更新操作,当数据页不在缓冲池中时,这些操作会被缓存起来,而非立即写入磁盘上的对应索引页面。设置一个较高的百分比可以更有效地利用更改缓冲来减少随机I/O,提高插入性能,但同时会占用更多的内存资源。
innodb_change_buffering :此参数定义了InnoDB更改缓冲的行为模式。默认值“all”意味着对所有类型的更改操作(inserts、deletes、purges)都会启用更改缓冲。其他可能的取值包括“none”(完全禁用更改缓冲)、“inserts”(仅针对插入操作启用更改缓冲)。根据不同的数据库工作负载和需求,可以选择适合的更改缓冲策略以达到最佳性能平衡。
两次写(Double Write)
两次写是一种崩溃恢复机制,用于防止数据页损坏。当InnoDB将一个数据页从缓冲池刷新到磁盘时,首先会将整个数据页复制到共享表空间的内存区域,然后再执行实际的磁盘写操作。如果在写入过程中发生崩溃,InnoDB可以在重启时从共享表空间的内存区域重新加载数据页,从而避免数据丢失或损坏。
mysql> show variables like '%double%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| innodb_doublewrite | ON |
| innodb_doublewrite_batch_size | 0 |
| innodb_doublewrite_dir | |
| innodb_doublewrite_files | 2 |
| innodb_doublewrite_pages | 4 |
+-------------------------------+-------+
innodb_doublewrite :这是一个布尔型变量,表示是否启用InnoDB的双写缓冲(Double Write Buffer)功能。当设置为ON时,意味着InnoDB会开启一个特殊的区域用来在将数据页写入表空间前先进行预写操作,防止因电源故障或系统崩溃导致的数据页损坏问题。启用该功能能增加数据的一致性和完整性,但也可能略微降低写性能。
innodb_doublewrite_batch_size :这个参数决定了每次提交时批量写入到双写缓冲区的数据页数量。如果值为0,则表示默认行为,即没有特别指定批量大小,每一页都会单独进行预写。非零值可以尝试减少磁盘I/O次数,但实际应用中此参数的调整需谨慎,因为它可能会影响数据一致性及恢复速度。
innodb_doublewrite_dir :这是用于指定双写缓冲区文件存放路径的目录名。如果为空,那么双写缓冲区将会被存储在InnoDB系统的共享表空间中。如果提供了特定目录,则双写缓冲区会被创建在这个目录下,但通常情况下不建议用户直接修改此参数。
innodb_doublewrite_files :这个参数定义了双写缓冲区使用的临时文件数量。在预写过程中,InnoDB会循环使用这些文件来保存待写入主表空间的数据页副本。默认值2意味着有两组文件用于轮换,这有助于在并发写入较多的情况下提供足够的空间。
innodb_doublewrite_pages :该参数标识每个双写缓冲文件中包含的连续未分配页面数。这些页面用于存储即将写入磁盘的数据页副本。当达到这个阈值后,InnoDB将触发一次同步写入操作,将缓冲中的数据刷入磁盘。默认值4表明每个双写缓冲文件中有4个连续页面用于预写。
自适应哈希索引(Adaptive Hash Index)
自适应哈希索引是一种动态创建和销毁的索引,用于提高查询性能。当InnoDB检测到某些页上的哈希查找频繁发生时,会自动为这些页创建哈希索引。这可以将B+树索引转换为更高效的哈希索引,从而提高查询速度。
mysql> show variables like '%innodb_adaptive_hash%';
+----------------------------------+-------+
| Variable_name | Value |
+----------------------------------+-------+
| innodb_adaptive_hash_index | ON |
| innodb_adaptive_hash_index_parts | 8 |
+----------------------------------+-------+
innodb_adaptive_hash_index :这个参数控制InnoDB是否启用自适应哈希索引功能。当设置为ON时,InnoDB会根据查询的访问模式动态地为经常被访问的索引创建哈希索引结构,以提高点查询性能。通过在内存中建立一个哈希表,可以实现对索引记录的快速查找,减少磁盘I/O操作。如果禁用此功能(OFF),则不会自动创建哈希索引。
innodb_adaptive_hash_index_parts :该参数表示自适应哈希索引内部划分的分区数。自适应哈希索引在内部是可分割的,分成多个部分有助于在多核处理器环境下更好地进行并发处理,并减少锁竞争。将此值设置得较高可以提高在高并发场景下的哈希索引性能,但也会占用更多的内存资源。默认情况下,MySQL通常将其设置为一个合理的数值,以平衡性能和内存使用之间的关系。
异步IO(Async IO)
异步IO是一种I/O模型,允许InnoDB在执行磁盘I/O操作时继续处理其他任务。这意味着InnoDB可以同时处理多个I/O请求,从而提高并发性能和系统吞吐量。
mysql> show variables like '%innodb_%aio%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_use_native_aio | ON |
+-----------------------+-------+
启用原生异步I/O可以减少数据库在等待I/O操作完成时产生的阻塞,特别是在高I/O负载或者大量数据需要存取的情况下,能够显著提升系统的响应速度和吞吐量。然而,并非所有操作系统都支持原生异步I/O,如果系统不支持(苹果的macOS),即使将此参数设置为ON,InnoDB也会自动回退到模拟异步I/O的方式。
刷新邻接页(Flush Neighbor Page)
刷新邻接页是一种优化策略,用于减少不必要的磁盘I/O操作。当InnoDB需要刷新一个数据页到磁盘时,会检查相邻的数据页是否也需要刷新。如果是,则会将这些相邻的数据页一起刷新,以减少磁盘I/O操作的数量。
mysql> show variables like '%innodb%neighbors%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_flush_neighbors | 0 |
+------------------------+-------+
innodb_flush_neighbors 参数决定了当一个脏页被刷新到磁盘时,是否同时将邻近的脏页也一并写入。这个参数值可以是0或1。
- 0 表示关闭邻接页刷新功能,仅针对当前需要刷新的单个脏页进行I/O操作,这样可以减少不必要的I/O开销和延迟,提高数据库在高并发事务下的性能。
- 1 表示开启邻接页刷新功能,当刷新一个脏页时,会检查其周围的邻接页是否也是脏页,并且一并写入磁盘。这种做法理论上可以优化磁盘顺序读写的效率,降低磁头移动带来的寻道时间,但在某些场景下可能会增加I/O操作量,影响性能。
默认情况下,MySQL通常设置为0,以适应现代硬件的特性,特别是在固态硬盘(SSD)等存储设备上,由于没有机械寻道时间,所以通常不需要考虑邻接页刷新来优化顺序写入。
启动、关闭与恢复
innodb_fast_shutdown
该参数是MySQL InnoDB存储引擎中的一个配置项,它控制了在数据库关闭时InnoDB表空间的清理方式和速度。
mysql> show variables like '%innodb%fast%';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| innodb_fast_shutdown | 1 |
+----------------------+-------+
innodb_fast_shutdown
参数有三个可能的取值(0、1、2),默认为1:
- 0 表示进行完全的慢速关闭。在这种模式下,InnoDB会在关闭前执行完整的清理和检查操作,包括刷新所有脏页到磁盘,以及对事务日志做完整校验等。这种方式最为安全,但关闭数据库所需的时间较长。如果在进行InnoDB 升级时,必须将这个参数调为0,然后再关闭数据库。
- 1 表示进行快速关闭。在这个模式下,InnoDB会尽可能地将脏页写入磁盘,并跳过一些耗时的完整性检查步骤,但仍保证数据的一致性。这样可以在牺牲部分恢复时间的前提下,提高数据库关闭的速度。
- 2 表示非常快的关闭。这种模式下,InnoDB不会确保所有的脏页都被刷到磁盘上,而是依赖于下次启动时的恢复机制来达到一致性状态。这通常会导致数据库重启时需要花费更多的时间来恢复未完成的事务和脏页。
因此,在实际应用中,根据业务需求权衡数据库关闭时间和安全性,可以选择合适的 innodb_fast_shutdown
值。如果更关心数据安全性和一致性,建议使用较低的数值;如果希望快速关闭数据库以减少维护窗口的时间,则可选择较高的数值,但需要注意在下次启动时可能会有额外的恢复开销。
innodb_force_recovery
该参数是MySQL InnoDB存储引擎中的一个关键变量,用于在数据库无法正常启动时强制InnoDB进入不同的恢复模式。
mysql> show variables like '%innodb%recovery%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_force_recovery | 0 |
+-----------------------+-------+
该参数的值通常介于0到6之间,每增加一级表示对数据库进行更严格、更保守的恢复处理。
-
当
innodb_force_recovery
设置为 0 时,这是默认值,意味着InnoDB将按照正常流程启动并尝试进行所有可能的数据恢复操作,包括回滚未完成事务、应用重做日志等。 -
当设置
innodb_force_recovery
的值大于0时,InnoDB会采取一系列逐渐加强的措施来确保数据库能够启动,即使这意味着牺牲数据的一致性或完整性。随着该参数值的增加,InnoDB将禁用某些可能导致循环或错误的操作,如:- 1(SRV_FORCE_IGNORE_CORRUPT):忽略检查到的 corrupt 页。
- 2(SRV_FORCE_NO_BACKGROUND):阻止 Master Thread 线程的运行,如 Master Thread 线程需要仅需 full purge 操作,而这会导致 crash。
- 3(SRV_FORCE_NO_TRX_UNDO):不进行事务的回滚操作。
- 4(SRV_FORCE_NO_IBUF_MERGE):不进行插入缓冲的合并操作。
- 5(SRV_FORCE_NO_UNDO_LOG_SCAN):不查看撤销日志(Undo Log),InnoDB 存储引擎会将未提交的事务视为已提交。
- 6(SRV_FORCE_NO_LOG_REDO):不进行前滚的操作。
需要注意的是,在设置了
innodb_force_recovery
大于0后,用户可以对表进行 select、create 和 drop 操作,但 insert、update 和 delete 这类 DML 操作时不允许的。
使用非零的 innodb_force_recovery
值是一种非常手段,主要用于紧急情况下的数据拯救,例如当数据库因各种原因(如硬件故障、数据损坏、不完整的事务等)无法正常启动时。启用这个参数可以帮助用户在不触发进一步问题的情况下启动数据库,并尽快导出重要数据以防止潜在数据丢失。 一旦数据库通过这种方式启动成功,应尽快备份重要数据,并在问题修复后立即将 innodb_force_recovery
参数还原为0,然后重启数据库恢复正常服务。
模拟故障
我们来做个实验,模拟故障的发生。在第一会话中,对一张接近1 000W行的InnoDB存储引擎表执行更新操作,但是完成后不要马上提交:
start transaction;
update Profile set password='';
–start transaction语句开启了事务,同时防止了自动提交的发生,update操作则会产生大量的回滚日志。这时,我们人为地kill掉MySQL数据库服务器。
ps-ef|grep mysqld
kill-9 pid
通过kill命令,我们人为地模拟了一次数据库宕机故障,当MySQL数据库下次启动时会对update的这个事务执行回滚操作,而这些信息都会记录在错误日志文件中,默认后缀名为err。如果查看错误日志文件,可得到如下结果:
090922 13:40:20 InnoDB:Started;log sequence number 6 2530474615
InnoDB:Starting in background the rollback of uncommitted transactions
090922 13:40:20 InnoDB:Rolling back trx with id 0 5281035,8867280 rows to undo
InnoDB:Progress in percents:1090922 13:40:20
090922 13:40:20[Note]/usr/local/mysql/bin/mysqld:ready for connections.
Version:'5.0.45-log'socket:'/tmp/mysql.sock'port:3306 MySQL Community
Server(GPL)
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
InnoDB:Rolling back of trx id 0 5281035 completed
090922 13:49:21 InnoDB:Rollback of non-prepared transactions completed
可以看到,如果采用默认的策略,即把innodb_force_recovery设为0,InnoDB会在每次启动后对发生问题的表执行恢复操作,通过错误日志文件,可知这次回滚操作需要回滚8 867 280行记录,总共耗时约9分多钟。
我们做再做一次同样的测试,只不过在启动MySQL数据库前将参数innodb_force_recovery设为3,然后观察InnoDB存储引擎是否还会执行回滚操作,查看错误日志文件,可看到:
090922 14:26:23 InnoDB:Started;log sequence number 7 2253251193
InnoDB:!innodb_force_recovery is set to 3!
090922 14:26:23[Note]/usr/local/mysql/bin/mysqld:ready for connections.
Version:'5.0.45-log'socket:'/tmp/mysql.sock'port:3306 MySQL Community
Server(GPL)
这里出现了“!”,InnoDB警告你已经将innodb_force_recovery设置为3,不会进行undo的回滚操作了。因此数据库很快启动完成,但是你应该很小心当前数据库的状态,并仔细确认是否不需要回滚操作。
参考博客:
https://blog.csdn.net/weixin_42653522/article/details/118807279
https://blog.csdn.net/weixin_45437022/article/details/121525939
https://blog.csdn.net/zhwxl_zyx/article/details/115717167
相关文章:
【数据库】MySQL InnoDB存储引擎详解 - 读书笔记
MySQL InnoDB存储引擎详解 - 读书笔记 InnoDB 存储引擎概述InnoDB 存储引擎的版本InnoDB 体系架构内存缓冲池LRU List、Free List 和 Flush List重做日志缓冲(redo log buffer)额外的内存池 存储结构表空间系统表空间独立表空间通用表空间undo表空间临时…...
GPT-2原理-Language Models are Unsupervised Multitask Learners
文章目录 前言GPT-1优缺点回顾GPT-1实验结果分析GPT-1缺陷分析 GPT-2训练数据OpenAI的野心预训练/微调的训练范式训练数据选择 模型结构和参数(更大的GPT-1)模型预训练训练参数 输入数据编码 总结 前言 首先强调一下,在看这篇文章之前&#…...
逆向案例十二——看准网企业信息json格式的信息
网址:【全国公司排行|排名榜单|哪家好】-看准网 打开开发者工具——刷新——网络——XHR——下滑页面加载新的页面——找到数据包 发现参数加密,返回的数据也进行了加密 按关键字在下方搜索 kiv进入第一个js文件 ctrlf打开文件里面的搜索框继续搜kiv找到…...
docker安装jenkins 2024版
docker 指令安装安装 docker run -d --restartalways \ --name jenkins -uroot -p 10340:8080 \ -p 10341:50000 \ -v /home/docker/jenkins:/var/jenkins_home \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /usr/bin/docker:/usr/bin/docker jenkins/jenkins:lts访问…...
输入url到页面显示过程的优化
浏览器架构 线程:操作系统能够进行运算调度的最小单位。 进程:操作系统最核心的就是进程,他是操作系统进行资源分配和调度的基本单位。 一个进程就是一个程序的运行实例。启动一个程序的时候,操作系统会为该程序创建一块内存&a…...
Linux(centos7)部署hive
前提环境: 已部署完hadoop(HDFS 、MapReduce 、YARN) 1、安装元数据服务MySQL 切换root用户 # 更新密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysqL-2022 # 安装Mysql yum库 rpm -Uvh http://repo.mysql.com//mysql57-community-release-el7-7.noarch.rpm # yu…...
LeetCode | 数组 | 双指针法 | 27. 移除元素【C++】
题目链接 1. 题目描述 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑…...
【Apache Doris】周FAQ集锦:第 2 期
【Apache Doris】周FAQ集锦:第 2 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目! 在这个栏目中,每周将筛选社区反馈的热门问题和话题,重点回答并进行深入探讨。旨在为广大用户和…...
jQuery(二)
文章目录 1.jQuery操作节点1.查找节点,修改属性1.基本介绍2.切换图片案例 2.创建节点1.基本介绍2.内部插入3.外部插入4.小结1.插入方法说明2.两种插入方法的区别 5.插入元素实例6.移动元素实例 3.删除节点1.基本介绍2.代码实例 4.复制节点1.基本介绍2.代码实例 5.替…...
MIT6.828 实验环境安装教程
Thanks:mit6.828环境搭建 - 人云我不亦云的文章 - 知乎 https://zhuanlan.zhihu.com/p/489921553 sudo make && make install install -d -m 0755 "/share/qemu" install: 无法创建目录 “/share”: 权限不够 make: *** [Makefile:382:…...
一文彻底搞清 Iterator(遍历器)概念及用法
目录 一、由来及意义 二、具体实现流程 三、具有默认 Iterator 接口的数据结构 四、调用 Iterator 接口的场合 五、总结 一、由来及意义 Javascript中表示“集合”的数据结构,主要是 Array、Object、Map、Set 这四种数据集合,除此之外,…...
稀疏矩阵的三元组表表示法及其转置
1. 什么是稀疏矩阵 稀疏矩阵是指矩阵中大多数元素为零的矩阵。 从直观上讲,当元素个数低于总元素的30%时,这样的矩阵被称为稀疏矩阵。 由于该种矩阵的特点,我们在存储这种矩阵时,如果直接采用二维数组,就会十分浪费…...
docker安装rabbitMQ,并且创建账号
# 创建docker容器启动,挂到后台运行 docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.13-management # 打开防火墙 sudo firewall-cmd --zonepublic --add-port5672/tcp --permanent sudo firewall-cmd --zonepublic --add-port15672/tcp --permanent s…...
wireshark解析grpc/protobuf的方法
1,wireshark需要安装3.20以上 下载地址:https://www.wireshark.org/ 2,如果版本不对,需要卸载,卸载方法: sudo rm -rf /Applications/Wireshark.app sudo rm -rf $HOME/.config/wireshark sudo rm -rf /…...
软件测试用例(2)
具体的设计方法 -- 黑盒测试 因果图 因果图是一种简化的逻辑图, 能直观地表明程序的输入条件(原因)和输出动作(结果)之间的相互关系. 因果图法是借助图形来设计测试用例的一种系统方法, 特别适用于被测试程序具有多种输入条件, 程序的输出又依赖于输入条件的各种情况. 因果图…...
集群式无人机仿真环境和数据集
仿真环境和数据集 Quick StartAcknowledgementsSwarmSim Quick Start Compiling tests passed on 20.04 with ros installed. You can just execute the following commands one by one. # Download the Simulator and run it wget https://cloud.tsinghua.edu.cn/library/34…...
IPSec VPN
IP Security,IP安全 1、特点 L3的VPN 缺:不支持组播、配置复杂、延迟增加、资源消耗较多 优:具备访问控制、密码学四个维度、抗重放打击 2、组件 ①安全协议 1)验证头技术(AH) IP协议号51 提供数据完整性检查,身份验证,抗重放攻击 无法做数据的机密性 AH的完…...
docker部署nacos,单例模式(standalone),使用内置的derby数据库,简易安装
文章目录 前言安装创建文件夹docker指令安装docker指令安装-瘦身版 制作docker-compose.yaml文件查看页面 前言 nacos作为主流的服务发现中心和配置中心,广泛应用于springcloud框架中,现在就让我们一起简易的部署一个单例模式的nacos,版本可…...
systemd监听服务配置文件更新自动重启服务
背景&需求 需要频繁更改一个服务的配置文件进行测试 实现 配置服务的systemd文件 vim /lib/systemd/system/xxx.service [Unit] Descriptionxxx daemon, A rule-based proxy in Go.[Service] Typesimple ExecStart/opt/xxx/xxx-d /etc/xxx/ Restartalways[Install] Wan…...
【yy讲解PostCSS是如何安装和使用】
🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…...
YOLO电动车检测识别数据集:12617张图像,yolo标注完整
YOLO电动车检测识别数据集:12617张图像,电动车一类,yolo标注完整,部分图像应用增强。 适用于CV项目,毕设,科研,实验等 需要此数据集或其他任何数据集请私信...
从汇编看函数调用
文章目录 函数调用流程栈相关寄存器及的作用简介寄存器功能指令功能 栈函数的括号{}正括号反括号 参数传递传值,变量不可改传指针,变量可改C 传引用 函数调用实例 函数调用流程 目标:函数调用前后栈保持不变 保存main函数的寄存器上下文移…...
node.js的错误处理
当我打开一个不存在的文件时,错误如下: 在读取文件里面写入console.log(err),在控制台中可以看到我的错误代码类型:文件不存在的错误代码 ENOENT。见更多错误代码---打开node.js官方API文档Error 错误 | N…...
shell的编写
文章目录 1.框架2.命令行3.获取用户命令字符串4.命令行字符串分割5.执行命令和内建命令6.完整代码: 1.框架 我们知道shell是一直存在的,所以首先我们第一步就是要搭建一个框架,使其一直存在。 那么也很简单,一个while循环就可以完…...
css心跳动画
图标引入 <img class"icon" src"heart.svg" alt"" srcset""> CSS代码 <style>.icon {animation:bpm 1s linear,pulse 0.75s 1s linear infinite;}keyframes pulse {from,75%,to {transform: scale(1);}25% {transform:…...
在 Amazon Timestream 上通过时序数据机器学习进行预测分析
由于不断变化的需求和现代化基础设施的动态性质,为大型应用程序规划容量可能会非常困难。例如,传统的反应式方法依赖于某些 DevOps 指标(如 CPU 和内存)的静态阈值,而这些指标在这样的环境中并不足以解决问题。在这篇文…...
【智能排班系统】快速消费线程池
文章目录 线程池介绍线程池核心参数核心线程数(Core Pool Size)最大线程数(Maximum Pool Size)队列(Queue)线程空闲超时时间(KeepAliveTime)拒绝策略(RejectedExecutionH…...
C语言——内存函数
前言: C语言中除了字符串函数和字符函数外,还有一些函数可以直接对内存进行操作,这些函数被称为内存函数,这些函数与字符串函数都属于<string.h>这个头文件中。 一.memcpy()函数 memcpy是C语言中的…...
ideaSSM图书借阅管理系统VS开发mysql数据库web结构java编程计算机网页源码maven项目
一、源码特点 SSM 图书借阅管理系统是一套完善的信息管理系统,结合SSM框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发),系统具有完整的源代码 和数据库,系统主…...
普联一面4.2面试记录
普联一面4.2面试记录 文章目录 普联一面4.2面试记录1.jdk和jre的区别2.java的容器有哪些3.list set map的区别4.get和post的区别5.哪个更安全6.java哪些集合类是线程安全的7.创建线程有哪几种方式8.线程的状态有哪几种9.线程的run和start的区别10.什么是java序列化11.redis的优…...
做造价在那个网站比较好/企业管理培训课程网课免费
目录 一:MVC架构模式简介 MVC架构模式: 二:Java中实现MVC说明、 1.Model(模型):***Service类: 2.Controller(控制器):Servlet类: 3.View&am…...
怎么做网站的导航/百度网站收录查询
一、联合查询在两种情况下可能用到:1、想要的结果在一条语句中会引起逻辑冲突,只能放在两条语句中是要使用联合查询2、一张表的数据量非常大时,会分隔成多张表存储,要查询时也要用到联合查询使用时要注意:1,…...
做ppt时网站怎么设计/无锡网站制作优化
Spring框架对于Java后端程序员来说再熟悉不过了,以前只知道它用的反射实现的,但了解之后才知道有很多巧妙的设计在里面。如果不看Spring的源码,你将会失去一次和大师学习的机会:它的代码规范,设计思想很值得学习。我们…...
中国疫情即将放开/外贸网站seo推广教程
遇到的几个问题: 1、android-ndk-r8d/build/core/build-binary.mk:41:***target file clean has both : and :: entries. Stop 解决办法:因为在libavfilter目录中的Makefile的末尾处多了Clean这个玩意儿将其注释掉或者删掉就可以了 2、parseutils.c文件多…...
网站建设要符合哪些标准/静态网站模板
整个视频打包下载地址:史上最全的数据结构视频教程系列分享之《[北大张铭 教学版]数据结构与算法(C)》,转载请保留出处和链接! 更多优秀资源请访问:我是码农 数据结构与算法是计算机专业一门相当重要的专业…...
wordpress放在其他端口/网络推广方法怎么做
第一步:OTA升级原理解释 TI官方WIKI详细介绍 http://processors.wiki.ti.com/index.php/OAD 1 解释:2 第一步:红色方框 1 Boot就像PC的BIOS,负责选择要运行的Image,是Image-A,还是Image-B.就像…...