搜索
首页数据库mysql教程MySQL系列:innodb引擎分析之文件IO_MySQL

innodb作为数据库引擎,自然少不了对文件的操作,在innodb中所有需要持久化的信息都需要文件操作,例如:表文件、重做日志文件、事务日志文件、备份归档文件等。innodb对文件IO操作可以是煞费苦心,其主要包括两方面,一个是对异步io的实现,一个是对文件操作管理和io调度的实现。在MySQL-5.6版本的innodb还加入了DIRECT IO实现。做了这么多无非是优化io操作的性能。在innodb的文件IO部分中,主要实现集中在os_file.*和fil0fil.*两个系列的文件当中,其中os_file*是实现基本的文件操作、异步IO和模拟异步IO。fil0fil.*是对文件io做系统的管理和space结构化。下面依次来介绍这两个方面的内容.

1.系统文件IO

在innodb中,文件的操作是比较关键的,innodb封装了基本的文件操作,例如:文件打开与关闭、文件读写以及文件属性访问等。这些是基本的文件操作函数封装。在linux文件的读写方面,默认是采用pread/pwrite函数进行读写操作,如果系统部支持这两个函数,innodb用lseek和read、write函数联合使用来达到效果. 以下是innodb文件操作函数: os_file_create_simple 创建或者打开一个文件 os_file_create 创建或者打开一个文件,如果操作失败会重试,直到成功 os_file_close 关闭打开的文件 os_file_get_size 获得文件的大小 os_file_set_size 设置文件的大小并以0填充文件内容 os_file_flush 将写的内容fsync到磁盘 os_file_read 从文件中读取数据 os_file_write 将数据写入文件 innodb除了实现以上基本的操作以外,还实现了文件的异步IO模型,在Windows下采用的IOCP模型来进行处理(具 体可以见网上的资料),在linux下是采用aio来实现的,有种情况,一种是通过系统本身的aio机制来实现,还有一种是 通过多线程信号模拟来实现aio.这里我们重点来介绍,为了实现aio,innodb定义了slot和slot array,具体数据结构如下:
typedef struct os_aio_slot_struct
{
     ibool	 is_read;                             /*是否是读操作*/
     ulint	 pos;                                    /*slot array的索引位置*/
     ibool	 reserved;                           /*这个slot是否被占用了*/
     ulint	 len;                                     /*读写的块长度*/
     byte*	 buf;                                   /*需要操作的数据缓冲区*/
     ulint	 type;                                   /*操作类型:OS_FILE_READ OS_FILE_WRITE*/
     ulint	 offset;                                 /*当前操作文件偏移位置,低32位*/
     ulint	 offset_high;                        /*当前操作文件偏移位置,高32位*/
     os_file_t	 file;                               /*文件句柄*/
     char*	 name;                               /*文件名*/
     ibool	 io_already_done;             /*在模拟aio的模式下使用,TODO*/
     void*	 message1;
     void*	 message2;
#ifdef POSIX_ASYNC_IO
     struct aiocb	control;                 /*posix 控制块*/
#endif
}os_aio_slot_t;

typedef struct os_aio_array_struct
{
 os_mutex_t	 mutex;          /*slots array的互斥锁*/
 os_event_t	 not_full;         /*可以插入数据的信号,一般在slot数据被aio操作后array_slot有空闲可利用的slot时发送*/
 os_event_t	 is_empty;       /*array 被清空的信号,一般在slot数据被aio操作后array_slot里面没有slot时发送这个信号*/

 ulint	 n_slots;                     /*slots总体单元个数*/
 ulint	 n_segments;             /*segment个数,一般一个对应n个slot,n = n_slots/n_segments,一个segment作为aio一次的操作范围*/
 ulint	 n_reserved;              /*有效的slots个数*/
 os_aio_slot_t*	slots;         /*slots数组*/

 os_event_t*	 events;         /*slots event array,暂时没弄明白做啥用的*/
}os_aio_array_t;
内存结构关系图:
\

2.文件管理的内存结构

在innodb中定义三种文件类型:表空间文件(ibdata*)、重做日志文件(ib_logfile*)和归档文件(ib_arch_log*)。一般innodb在运行的过程中,会同时打开很多个文件,这就要求对文件进行系统的管理和控制。在innodb中定义了一套基于fil_system_t、fil_space_t和fil_node_t的内存管理结构。每个文件对应的是一个fil_node_t,fil_node是存储的最小单元,多个同一模块的fil_node组成一个fil_space_t,所有的space组成一个fil_system_t,在innodb引擎里,只有一个fil_system_t对象。

fil_system_t管理着全局的文件操作资源,例如:文件打开的数量、打开文件的信号控制、fil_space_t的管理和索引等。以下是fil_system_t的结构定义:

 

typedef struct fil_system_struct
{
     mutex_t	 mutex;              /*file system的保护锁*/
     hash_table_t*	spaces;     /*space的哈希表,用于快速检索space,一般是通过space id查找*/
     ulint	 n_open_pending;  /*当前有读写IO操作的fil_node个数*/
     ulint	 max_n_open;         /*最大允许打开的文件个数*/
     os_event_t	 can_open;    /*可以打开新的文件的信号*/
 
    UT_LIST_BASE_NODE_T(fil_node_t) LRU;       /*最近被打开操作过的文件,用于快速定位关闭的fil_node*/
    UT_LIST_BASE_NODE_T(fil_node_t) space_list;	 /*file space的对象列表*/
}fil_system_t;
值得注意的是space的哈希表和LRU,这里为什么会出现用hash table来索引space呢?因为在实际的数据库系统中,fil_space_t是会非常多的,用哈希表能快速定位到需要操作的fil_space_t。LRU是用于保存最近被打开和被操作过的fil_node,为了避免频发的关闭和打开文件,LRU保存一定数量(500)的最近打开过的文件,这样可以提高系统的效率。

 

fil_space_t是用于管理同一模块的file_node,上层模块操作文件不是以文件名来做操作关联的,而是用space_id,

也就是说,所有的文件操作是通过space为单位进行操作的。fil_space支持三种类型,分别是:
FIL_TABLESPACE 表空间space
FIL_LOG 重做日志space
FIL_ARCHI_LOG 归档日志space

fil_space_t的定义如下:

 

struct fil_space_struct
{
     char*	 name;                     /*space名称*/
     ulint	 id;                            /*space id*/
     ulint	 purpose;                 /*space的类型,主要有space table, log file和arch file*/
     ulint	 size;                         /*space包含的页个数*/
     ulint	 n_reserved_extents; /*预留的页个数*/
     hash_node_t	 hash;          /*chain node的HASH表*/
     rw_lock_t	 latch;               /*space操作保护锁,用于多线程并发*/
     ibuf_data_t*	ibuf_data;   /*space 对应的insert buffer*/
     ulint	 magic_n;                 /*魔法校验字*/

     UT_LIST_BASE_NODE_T(fil_node_t) chain;
     UT_LIST_NODE_T(fil_space_t)	 space_list;
};
fil_space通常是由一组文件组成,例如重做日志,一般是有3个文件组成一个group space用于重做日志记录。space通过成员latch可以支持多线程并发的。在innodb文件操作中,主要是通过space来做控制,以下是它的控制函数:
fil_space_create 创建一个fil_space
fil_space_free 销毁一个fil_space
fil_space_truncate_start 从space中删除fil_node,删除的总数据长度为trunc_len
fil_node_create 创建一个fil_node并加入到对应的space当中
fil_space_get_size 获得space的空间大小,以page为单位记
fil_io 指定space的io操作
fil_aio_wait aio异步方式的io操作等待,并根据完成状态更新space状态
fil_flush 指定space进行数据刷盘
fil_node_t是对单个文件进行管理,主要是管理文件的打开状态、文件句柄信息、文件的page数量和更新状态等。

 

其结构定义如下:

 

struct fil_node_struct
{
     char*	 name;                         /*文件路径名*/
     ibool	 open;                         /*文件是否被打开*/
     os_file_t	handle;                  /*文件句柄*/
     ulint	 size;                             /*文件包含的页个数,一个页是16K*/
     ulint	 n_pending;                 /*等待读写IO操作的个数*/
     ibool	 is_modified;               /*是否有脏也存在,flush是根据这个标志进行刷盘的*/
     ulint	 magic_n;                     /*魔法校验字*/
     UT_LIST_NODE_T(fil_node_t) chain;
     UT_LIST_NODE_T(fil_node_t) LRU;
};

值得注意的是当外部调用了fil_flush时,判断一个fil_node是否需要刷盘的必要条件是:
文件必须是打开的 open = TRUE
文件存在内存和硬盘数据不一致 is_modified = TRUE

 

 

了解了他们三者的基本定义后,那他们之间的关系是怎么的?不用文字叙述,看下面的内存结构关系图:

 

\

 

在了解了他们之间的基本关系后,那么一个io操作是怎么进行的?在这个模型里,一个io操作提交和被运行是比较复杂的。具体流程如下: 1.外部模块提交一个fil_io, 先会进行基本的io操作类型的判断和文件打开方式的判断。 2.然后进行对正在进行io操作的计数做判断,如果正在进行的io数量 > 最大文件打开数量的四分之三,唤醒所有aio的操作线程进行io处理,并进行sleep等待。 3.如果正在进行的io数量 = 最大文件打开数量,唤醒所有的aio操作线程进行io处理,并等待fil_system_t的can_open信号。 4.如果不满足2和3,找到需要受理io操作的space和node,并打开node对应的文件,打开文件时会对打开文件数量限制做判断,如果当前打开文件操作io的数量 + LRU里已经打开文件的数量>= 最大文件打开数量时,会取出LRU中最后一个fil_node进行文件关闭。然后在对新的io操作的fil_node文件进行打开。 5.fil_node文件打开后,调用os_aio进行io操作提交,然后等待io操作完成 6. io操作完成后,将完成io操作的fil_node放入LRU的第一个位置,并更改对应的fil_system/fil_space/fil_node的状态,最后触发一个fil_system的can open信号。 7.监听can_open的线程收到这个信号后,会跳到第4步进行自己的io操作提交。 流程图如下: \

 

3总结

总体来说,innodb的文件IO涉及到知识面很多,可以能短时间无法完全理解透彻,一般在阅读源码的时候可以做一些基本的单元测试,这样有助于理解。弄清楚innodb的文件IO操作是非常有必要的,因为文件IO操作模块直接影响对innodb的日志系统的理解、表空间系统的理解。而且Innodb在文件IO模块的改进还是比较大的,尤其是引入Direct IO后。Direct IO很多数据库都在用这个技术,除了innodb,oracle和淘宝的oceanbase都使用了这个技术, 关于Direct IO网络上资料很多,可以自行结合MySQL-5.6的innodb来做研究。
声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
如何识别和优化MySQL中的慢速查询? (慢查询日志,performance_schema)如何识别和优化MySQL中的慢速查询? (慢查询日志,performance_schema)Apr 10, 2025 am 09:36 AM

要优化MySQL慢查询,需使用slowquerylog和performance_schema:1.启用slowquerylog并设置阈值,记录慢查询;2.利用performance_schema分析查询执行细节,找出性能瓶颈并优化。

MySQL和SQL:开发人员的基本技能MySQL和SQL:开发人员的基本技能Apr 10, 2025 am 09:30 AM

MySQL和SQL是开发者必备技能。1.MySQL是开源的关系型数据库管理系统,SQL是用于管理和操作数据库的标准语言。2.MySQL通过高效的数据存储和检索功能支持多种存储引擎,SQL通过简单语句完成复杂数据操作。3.使用示例包括基本查询和高级查询,如按条件过滤和排序。4.常见错误包括语法错误和性能问题,可通过检查SQL语句和使用EXPLAIN命令优化。5.性能优化技巧包括使用索引、避免全表扫描、优化JOIN操作和提升代码可读性。

描述MySQL异步主奴隶复制过程。描述MySQL异步主奴隶复制过程。Apr 10, 2025 am 09:30 AM

MySQL异步主从复制通过binlog实现数据同步,提升读性能和高可用性。1)主服务器记录变更到binlog;2)从服务器通过I/O线程读取binlog;3)从服务器的SQL线程应用binlog同步数据。

mysql:简单的概念,用于轻松学习mysql:简单的概念,用于轻松学习Apr 10, 2025 am 09:29 AM

MySQL是一个开源的关系型数据库管理系统。1)创建数据库和表:使用CREATEDATABASE和CREATETABLE命令。2)基本操作:INSERT、UPDATE、DELETE和SELECT。3)高级操作:JOIN、子查询和事务处理。4)调试技巧:检查语法、数据类型和权限。5)优化建议:使用索引、避免SELECT*和使用事务。

MySQL:数据库的用户友好介绍MySQL:数据库的用户友好介绍Apr 10, 2025 am 09:27 AM

MySQL的安装和基本操作包括:1.下载并安装MySQL,设置根用户密码;2.使用SQL命令创建数据库和表,如CREATEDATABASE和CREATETABLE;3.执行CRUD操作,使用INSERT,SELECT,UPDATE,DELETE命令;4.创建索引和存储过程以优化性能和实现复杂逻辑。通过这些步骤,你可以从零开始构建和管理MySQL数据库。

InnoDB缓冲池如何工作,为什么对性能至关重要?InnoDB缓冲池如何工作,为什么对性能至关重要?Apr 09, 2025 am 12:12 AM

InnoDBBufferPool通过将数据和索引页加载到内存中来提升MySQL数据库的性能。1)数据页加载到BufferPool中,减少磁盘I/O。2)脏页被标记并定期刷新到磁盘。3)LRU算法管理数据页淘汰。4)预读机制提前加载可能需要的数据页。

MySQL:初学者的数据管理易用性MySQL:初学者的数据管理易用性Apr 09, 2025 am 12:07 AM

MySQL适合初学者使用,因为它安装简单、功能强大且易于管理数据。1.安装和配置简单,适用于多种操作系统。2.支持基本操作如创建数据库和表、插入、查询、更新和删除数据。3.提供高级功能如JOIN操作和子查询。4.可以通过索引、查询优化和分表分区来提升性能。5.支持备份、恢复和安全措施,确保数据的安全和一致性。

与MySQL中使用索引相比,全表扫描何时可以更快?与MySQL中使用索引相比,全表扫描何时可以更快?Apr 09, 2025 am 12:05 AM

全表扫描在MySQL中可能比使用索引更快,具体情况包括:1)数据量较小时;2)查询返回大量数据时;3)索引列不具备高选择性时;4)复杂查询时。通过分析查询计划、优化索引、避免过度索引和定期维护表,可以在实际应用中做出最优选择。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用