【MySQL技术内幕】3.6-InnoDB存储引擎文件

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【MySQL技术内幕】3.6-InnoDB存储引擎文件

之前介绍的文件都是 MySQL数据库本身的文件,和存储引擎无关。除了这些文件外,每个表存储引擎还有其自己独有的文件。本节将具体介绍与 InnoDB存储引擎密切相关的文件,这些文件包括重做日志文件、表空间文件。

1、表空间文件

InnoDB采用将存储的数据按表空间(tablespace)进行存放的设计。在默认配置下会有一个初始大小为10MB,名为 ibdata1的文件。该文件就是默认的表空间文件(tablespace file),用户可以通过参数 innodb_data_file_path对其进行设置,格式如下

innodb_data_file_path=datafile_spec1[;datafile_spec2]...

用户可以通过多个文件组成一个表空间,同时制定文件的属性,如:

[mysqld]
innodb_data_file_path=/db/ibdata1:2000M;/dr2/db/ibdata2:2000M:autoextend

这里将/db/ibdata1和/dr2/db/ibdata2两个文件用来组成表空间。若这两个文件位于不同的磁盘上,磁盘的负载可能被平均,因此可以提高数据库的整体性能。同时,两个文件的文件名后都跟了属性,表示文件 idbdata1的大小为2000MB,文件 ibdata2的大小为2000MB,如果用完了这2000MB,该文件可以自动增长(autoextend)设置 innodb_data_file_path参数后,所有基于 InnoDB存储引擎的表的数据都会记录到该共享表空间中。若设置了参数 innodb_file_per_table,则用户可以将每个基于InnoDB存储引擎的表产生一个独立表空间。独立表空间的命名规则为:表名.ibd。通过这样的方式,用户不用将所有数据都存放于默认的表空间中。下面这台 MySQL数据库服务器设置了 innodb_file_per_table,故可以观察到:

mysql> SHOW VARIABLES LIKE 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.00 sec)
 
mysql> system sudo ls /usr/local/mysql/data/mysql
columns_priv.MYD    event.MYI     help_category.frm   innodb_table_stats.frm    procs_priv.MYD      slave_master_info.frm   tables_priv.MYI     time_zone_transition_type.frm
columns_priv.MYI    event.frm     help_category.ibd   innodb_table_stats.ibd    procs_priv.MYI      slave_master_info.ibd   tables_priv.frm     time_zone_transition_type.ibd
columns_priv.frm    func.MYD      help_keyword.frm    ndb_binlog_index.MYD    procs_priv.frm      slave_relay_log_info.frm  time_zone.frm     user.MYD
db.MYD        func.MYI      help_keyword.ibd    ndb_binlog_index.MYI    proxies_priv.MYD    slave_relay_log_info.ibd  time_zone.ibd     user.MYI
db.MYI        func.frm      help_relation.frm   ndb_binlog_index.frm    proxies_priv.MYI    slave_worker_info.frm   time_zone_leap_second.frm user.frm
db.frm        general_log.CSM     help_relation.ibd   plugin.frm      proxies_priv.frm    slave_worker_info.ibd   time_zone_leap_second.ibd
db.opt        general_log.CSV     help_topic.frm      plugin.ibd      server_cost.frm     slow_log.CSM      time_zone_name.frm
engine_cost.frm     general_log.frm     help_topic.ibd      proc.MYD      server_cost.ibd     slow_log.CSV      time_zone_name.ibd
engine_cost.ibd     gtid_executed.frm   innodb_index_stats.frm    proc.MYI      servers.frm     slow_log.frm      time_zone_transition.frm
event.MYD     gtid_executed.ibd   innodb_index_stats.ibd    proc.frm      servers.ibd     tables_priv.MYD     time_zone_transition.ibd

由于设置参数 innodb_file_per_table=ON,因此产生了单独的.ibd独立表空间文件。需要注意的是,这些单独的表空间文件仅存储该表的数据、索引和插入缓冲 BITMAP等信息,其余信息还是存放在默认的表空间中。图显示了 InnoDB存储引擎对于文件的存储方式:

image.png

2、重做日志文件

在默认情况下,在 InnoDB存储引擎的数据目录下会有两个名为 ib_logfile0和ib_logfile1的文件。在 MySQL官方手册中将其称为 InnoDB存储引擎的日志文件,不过更准确的定义应该是重做日志文件(redo log file)。为什么强调是重做日志文件呢?因为重做日志文件对于 InnoDB存储引擎至关重要,它们记录了对于 InnoDB存储引擎的事务日志。

当实例或介质失败(media failure)时,重做日志文件就能派上用场。例如,数据库由于所在主机掉电导致实例失败, InnoDB存储引擎会使用重做日志恢复到掉电前的时刻,以此来保证数据的完整性。

每个 InnoDB存储引擎至少有1个重做日志文件组( group),每个文件组下至少有2个重做日志文件,如默认的 ib_logfile0和 ib_logfile1。为了得到更高的可靠性,用户可以设置多个的镜像日志组(mirrored log groups),将不同的文件组放在不同的磁盘上,以此提高重做日志的高可用性。在日志组中每个重做日志文件的大小一致,并以循环写入的方式运行。InnoDB存储引擎先写重做日志文件,当达到文件的最后时会切换至重做日志文件2,再当重做日志文件2也被写满时,会再切换到重做日志文件1中。

下图显示了一个拥有3个重做日志文件的重做日志文件组。

image.png

下列参数影响着重做日志文件的属性:

  • innodb_log_file_size
  • innodb_log_files_in_group
  • innodb_mirrored_log_groups
  • innodb_log_group_home_dir

参数 innodb_log_file_size指定每个重做日志文件的大小。在 InnoDB1.2.x版本之前,重做日志文件总的大小不得大于等于4GB,而1.2.x版本将该限制扩大为了512GB参数 innodb_log_files_in_group指定了日志文件组中重做日志文件的数量,默认为2。

参数innodb _mirrored_log_groups指定了日志镜像文件组的数量,默认为1,表示只有一个日志文件组,没有镜像。若磁盘本身已经做了高可用的方案,如磁盘阵列,那么可以不开启重做日志镜像的功能。最后,参数 innodb_log_ group_home_dir指定了日志文件组所在路径,默认为./,表示在 MySQL数据库的数据目录下。

重做日志文件的大小设置对于 InnoDB存储引擎的性能有着非常大的影响。一方面重做日志文件不能设置得太大,如果设置得很大,在恢复时可能需要很长的时间方面又不能设置得太小了,否则可能导致一个事务的日志需要多次切换重做日志文件。

此外,重做日志文件太小会导致频繁地发生 async checkpoint,导致性能的抖动。例如,用户可能会在错误日志中看到如下警告信息: image.png

上面错误集中在 InnoDB: ERROR the age of the last checkpoint is 9433645, InnoDB which exceeds the log group capacity 9433498。这是因为重做日志有一个 capacity变量,该值代表了最后的检查点不能超过这个阈值,如果超过则必须将缓冲池( innodb buffer pool)中脏页列表(flush list)中的部分脏数据页写回磁盘,这时会导致用户线程的阻塞。

也许有人会问,既然同样是记录事务日志,和之前介绍的二进制日志有什么区别?

首先,二进制日志会记录所有与 MySQL数据库有关的日志记录,包括 InnoDB、MyISAM、Heap等其他存储引擎的日志。而 InnoDB存储引擎的重做日志只记录有关该存储引擎本身的事务日志。

其次,记录的内容不同,无论用户将二进制日志文件记录的格式设为 STATEMENT还是ROW,又或者是 MIXED,其记录的都是关于一个事务的具体操作内容,即该日志是逻辑日志。而 InnoDB存储引擎的重做日志文件记录的是关于每个页(Page)的更改的物理情况。

此外,写入的时间也不同,二进制日志文件仅在事务提交前进行提交,即只写磁盘一次,不论这时该事务多大。而在事务进行的过程中,却不断有重做日志条目(redo entry)被写入到重做日志文件中。

在InnoDB存储引擎中,对于各种不同的操作有着不同的重做日志格式。到 InnoDB 1.2.x版本为止,总共定义了51种重做日志类型。虽然各种重做日志的类型不同,但是它们有着基本的格式,下图显示了重做日志条目的结构:

image.png

从表可以看到重做日志条目是由4个部分组成:

  • redo_log_type占用1字节,表示重做日志的类型
  • space表示表空间的ID,但采用压缩的方式,因此占用的空间可能小于4字节
  • page_no表示页的偏移量,同样采用压缩的方式
  • redo_log_body表示每个重做日志的数据部分,恢复时需要调用相应的函数进行解析

写人重做日志文件的操作不是直接写,而是先写入一个重做日志缓冲( redo log buffer)中,然后按照一定的条件顺序地写入日志文件。下图很好地诠释了重做日志的写人过程。

image.png

从重做日志缓冲往磁盘写入时,是按512个字节,也就是一个扇区的大小进行写入。因为扇区是写人的最小单位,因此可以保证写入必定是成功的。因此在重做日志的写入过程中不需要有 doublewrite。

前面提到了从日志缓冲写入磁盘上的重做日志文件是按一定条件进行的,那这些条件有哪些呢?在主线程中每秒会将重做日志缓冲写入磁盘的重做日志文件中,不论事务是否已经提交。另一个触发写磁盘的过程是由参数 innodb_flush_log_at_trx_commit控制,表示在提交( commit)操作时,处理重做日志的方式。

参数 innodb_flush_log_at_trx_commit的有效值有0、1、2。0代表当提事务时够并不将事务的重做日志写入磁盘上的日志文件,而是等待主线程每秒的刷新。1和2不同的地方在于:1表示在执行comm时将重做日志缓冲同步写到磁盘,即伴有 fsync的调用。2表示将重做日志异步写到磁盘,即写到文件系统的缓存中。因此不能完全保证在执行 commit时肯定会写入重做日志文件,只是有这个动作发生。

因此为了保证事务的ACID中的持久性,必须将 innodb_flush_log_ at_trx_commit设置为1,也就是每当有事务提交时,就必须确保事务都已经写入重做日志文件。那么当数据库因为意外发生宕机时,可以通过重做日志文件恢复,并保证可以恢复已经提交的事务。而将重做日志文件设置为0或2,都有可能发生恢复时部分事务的丢失。不同之处在于,设置为2时,当 MySQL数据库发生宕机而操作系统及服务器并没有发生宕机时,由于此时未写入磁盘的事务日志保存在文件系统缓存中,当恢复时同样能保证数据不丢失。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
24天前
|
存储 关系型数据库 MySQL
|
24天前
|
存储 关系型数据库 MySQL
|
21天前
|
存储 关系型数据库 MySQL
|
26天前
|
存储 关系型数据库 MySQL
|
27天前
|
存储 关系型数据库 MySQL
|
1月前
|
Oracle 关系型数据库 MySQL
实时计算 Flink版产品使用问题之假如mysql的binlog有很多个文件,按什么顺序扫描
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
29天前
|
存储 关系型数据库 MySQL
MySQL数据库进阶第一篇(存储引擎与Linux系统上安装MySQL数据库)
MySQL数据库进阶第一篇(存储引擎与Linux系统上安装MySQL数据库)
|
15天前
|
存储 关系型数据库 MySQL
MySQL存储引擎
MySQL存储引擎
13 0
|
20天前
|
存储 关系型数据库 MySQL
技术笔记:MySQL数据库优化详解(收藏)
技术笔记:MySQL数据库优化详解(收藏)
20 0
|
20天前
|
SQL 关系型数据库 MySQL
技术笔记:python连接mysql数据库
技术笔记:python连接mysql数据库
15 0