innodb学习笔记(一)  aio的使用

innodb学习笔记(一)  aio的使用

      这里先以mysql 5.7.26版本进行学习。

一. 四种IO线程及线程数量

      分为读线程,写线程,log io线程和buf io线程,重点在innobase/os/Osofile.cc这个文件里。

1.1 aio读写线程

      innodb可以配置aio线程的数量,在图1-1某线上实例的my.cnf中可以看到读线程和写线程数量的配置,这里一例读写线程数量各自为8。后文都以读8写8为例说明。

                                

                                            图 1-1 某线上实例线程数量配置

      实际代码中srv0start.cc负责aio的初始化,这里实际对应srv_n_read_io_threads和srv_n_write_io_threads两个参数分别指定负责读IO的线程数量和负责写IO的线程数量;

      当然除了指定的读线程和写线程外,还有一个log io thread和ibuf io thread。所以实际的io线程总数srv_n_file_io_threads就是:

srv_n_file_io_threads = srv_n_read_io_threads + srv_n_write_io_threads + 2

      以上这些逻辑在innobase_start_or_create_for_mysql()初始化中可以看到。

      综上,一个mysql实例中有:

  • 4种不同的IO线程;
  • n个read io线程,n个write io线程,一个log io线程,一个buf io线程;

二. aio管理结构

      核心是定义在os0file.cc中的class AIO结构,如下图列出了其中所有的类成员和部分重要类方法。

                                    

                                                            图 2-1 aio类

       其实全局来看AIO结构是一个工厂,并不会有实体,该工厂可以根据参数分别创建read io,write io,log io和ibuf io这四种不同的AIO实例,这些实例被创建好后赋给相应的static AIO *指针,之后在db实例的整个运行过程中就可以通过诸如s_reads, s_writes这样的static指针来调用相应的AIO实例。

2.1 AIO结构中重要的成员

  • m_mutex

对于wirte和read类型的AIO,会有多个线程来操作AIO实例,因此需要mutex进行互斥;

  • m_slots

一个AIO包含的所有的slot实例,存储在该向量中,每个slot代表一个io请求,可能是读,也可能是写。slot的数量为相应的线程数量 n 乘以系统规定的该类线程允许的pending aio的数量,其中线程数量n在上一节已经给出,而该类线程允许pending aio的数量为硬编码n * OS_AIO_N_PENDING_IOS_PER_THREAD为256;

对于read/write io类型的AIO,slot数量为线程数n * 256,这些slot需要均分成m_n_segments份,其实m_n_segments就是线程数量;

  • m_n_segments

所有的slot会被分隔成m_n_segments份,其实就是io线程数量,一个io线程可以以io_getevents等待在任一segment上,其实一个segment就对应一个io_ctx;可以推断,针对某一种io线程,比如write io数量为8,那么m_n_segments值就为8,slots被分隔成8个segment,每个segment包含的slot数量为256;从后续代码可以看到,每个io_ctx在被io_setup和io getevents时,参数nr和max_nr都为256;

                                                                            图 2-2 slot的分割

实际上看起来分成多个segments的主要目的除了提前分配好m_n_segments个io_ctx外,可以把物理地址相近的io放入到同一segments中方便可能存在的io merge,如reserve_slot()中所示;

但是,reserve_slot()中选择了一个segment后,io并不一定真的能放入这个segment中,只是从这个segment开始搜索第一个未被占用的slot而已;

  • m_not_full

条件变量,当当前AIO的slots从full变成not full时就释放这个条件变量,表示有空余的slot可以用来提交io请求了,如reserve_slot()中所示;

  • m_is_empty

条件变量,当当前AIO的被reserved的slot数量从0变成1时该条件会被hold,见reserve_slot();当reserved的slot数量从1变成0时会被释放,见AIO::release();

从代码来看,只有s_write类型的AIO会存在对该条件变量的wait,主要是log file和db wirte file的flush的前置操作;

  • m_n_reserved

该AIO中被占用的slot总数,维护这个数字主要是做为m_not_full和m_is_empty两个条件变量操作的依据;

  • m_aio_ctx

n_segments个aio上下文组成的数组,正好每个IO线程对应一个;

  • m_events

n_slots个aio_event组成的数组,aio event完成后,io_getevents将io_event保存的位置;

  • s_log/s_writes/s_reads/s_ibuf

四种不同类型io线程对应的AIO实例; 

2.2 Slot结构

      一个Slot结构代表一个io请求。Slot结构非常容易理解,该IO相关的一些信息。

                                            

                                                                   图 2-3 slot结构

三. AIO初始化

aio的初始化从os_aio_init,可以分为两个范畴:

  1. AIO范畴:分别为各种io类型创建AIO实例,也就是调用AIO::create()函数,对于每个AIO实例,就是执行构造函数和init成员方法;
  2. linux aio范畴:对于每一个AIO实例内部,io_setup准备m_n_segment个aio_ctx,也就是每个io线程对应一个;每个aio_ctx的max_event值为该AIO的m_slots.size()除以m_n_segment,其实就是256;这些操作是在init_linux_native_aio()中完成;

以上两个操作还包含了为AIO实例以及Slot实例的成员变量赋初始值。

                    

                                                                     图 3-1 aio初始化函数调用

四. AIO线程逻辑

在代码中多处看到诸如# ifdef UNIV_PFS_THREAD这样的宏,这里pfs是指performance schema instrumented,这是用于监控MySQL server在一个较低级别的运行过程中的资源消耗、资源等待等情况的一个模块,参考https://blog.csdn.net/qq_35068291/article/details/105921515

      AIO逻辑当然包括提交IO请求(submit)和IO收割(getevents)两部分,实际上innodb里的AIO逻辑主要是在收割上,前文所述的IO线程都是在做收割工作,所以我们先来看下收割逻辑。

4.1 收割

       AIO线程主函数是io_handler_thread,在innobase_start_or_create_for_mysql( )中可以看到create了srv_n_file_io_threads个AIO线程均是以io_handler_thread为线程主函数。                     

                                                                              图 4-1 aio收割逻辑

      如图4-1所示,其实主函数就是不断循环调用fil_aio_wait函数,fil_aio_wait则负责实际的对segment中aio_ctx的io_getevents和善后工作。

      其中os_aio_handler是实际的收割动作,segment实际指定了aio_ctx,其他参数其实都是输出型结果参数。

4.2 提交

linux_dispatch通过io_submit提交aio,层层回推,aio的submit入口是fil_io函数。

fil_io一个主要的使用场景是刷脏页,逻辑比较复杂,准备后面专门分析,这里画了一个主要的逻辑图。

https://www.processon.com/view/link/5f6602cee401fd2ad7eb852

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值