asyn io

来源:互联网 发布:kali linux渗透测试 编辑:程序博客网 时间:2024/06/06 02:54

 

 

等待的线程

io_handler_thread 等线程的主函数,每个线程都对应一个对列,read,write是4个线程对应一个队列

fil_aio_wait 主要是等待IO结束

buf_page_io_complete 读页面的内容,释放对页面的锁

 

读页面的过程

buf_read_page_low   Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock released by an i/o-handler thread.

fil_io

os_aio

   os_aio_array_reserve_slot 上队列里面找到空闲的,调用io_prep_pread 或 io_prep_pwrite

   os_aio_linux_dispatch 调用 io_submit, 一个页面就调用,而不是多个页面一块调

 

 

read ahead

http://dev.mysql.com/doc/refman/5.5/en/innodb-performance-read_ahead.html

 

 

 

 


看来mysql已放弃,读一个页面时,把这个页面相邻的页面也读进来的random read ahead,
要执行liner read ahead,需要有三个前提条件

1。当前正在读的是border页面,并且是第一次读入内存,当等待这个要读的页面读完后

2。在当前这个页面区间内,已有阀值个页面被读入,默认的阀值是56,最少有56个相邻页面,才进行read ahead下一个区间,是循环64次,每次读入一个页面

3。本页面所在的区间,和下次要读的区间是物理相邻的,并且不等待返回这个区间的返回

 

比如:

0--63 64--127 这个区间中,当读到63页面时,把下一个区间64个页面读入

 

 

 

win下面缓存读写和直接读写的不同点,对于直接读写对应的参数值为async_unbuffered,对于缓存读写对应的参数值为normal。主要是分析openwrite的不同。

1Win直接读写。

mysql帮助文档里面指明在win下面只能使用async_unbuffered并且不能更改,这个参数是使用不带系统缓存的异步读写方式。数据文件和日志都走的是Windows native AIO这条路,只不过日志在wirte之后,会等待异步写返回。

Open:

CreateFile((LPCTSTR) name,

                      GENERIC_READ | GENERIC_WRITE,

                      share_mode,   

                      NULL,

                      create_flag,

                      FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,

                      NULL);

Write: 对于数据文件和日志文件是一样的

WriteFile(file, buf, (DWORD)n, &len, &(slot->control));

在日志的异步写完之后,会有一个WaitForSingleObject操作,等待日志写操作返回。

 

2Win缓存读写

Win下面通过查看源码,发现还支持normal这个值,当设置这个值时,实现的就是缓存读写,没有用到任何Simulated AIOWindows native AIO的数据结构和线程,数据文件和日志文件的读写操作就是直接调用系统函数。

Open: 对于数据文件和日志文件是一样的

CreateFile((LPCTSTR) name,

                      GENERIC_READ | GENERIC_WRITE,

                      share_mode,   

                      NULL,

                      create_flag,

                      0,

                      NULL);

Write:对于数据文件和日志文件是一样的

WriteFile(file, buf, (DWORD) n, &len, NULL);

 

 

以下分析Linux下面缓存读写和直接读写的不同点,对于直接读写对应的参数值为O_DIRECT,对于缓存读写对应的参数值为O_DSYNCfdatasync

1Linux下面直接读写

这个参数是使用不带系统缓存的异步读写方式。数据文件走的是Linux native AIO这条路,日志文件走的是缓存读写这条路。

Open:

对于数据文件:open(name,  O_RDWR | O_DIRECT,  os_innodb_umask);

对于日志文件:open(name,  O_RDWR,  os_innodb_umask);

Write:

对于数据文件:走的是Linux native AIO这条路

对于日志文件:pwrite(file, buf, (ssize_t)n, offs);

 

2Linux下面缓存读写O_DSYNC

数据文件和日志文件走的是缓存读写这条路。日志文件中打开时多了一个参数。

Open:

对于数据文件:open(name,  O_RDWR ,  os_innodb_umask);

对于日志文件:open(name,  O_RDWR | O_SYNC,  os_innodb_umask);

Write: 对于数据文件和日志文件是一样的

pwrite(file, buf, (ssize_t)n, offs);

 

3Linux下面缓存读写fdatasync

数据文件和日志文件走的是缓存读写这条路。

Open: 对于数据文件和日志文件是一样的

open(name,  O_RDWR ,  os_innodb_umask);

Write: 对于数据文件和日志文件是一样的

pwrite(file, buf, (ssize_t)n, offs);

 

从上面可以看过,对于直接读写,在winLinux,对于日志的实现是不一样的,win下面是直接异步读写,加一个等待操作;Linux下面是缓存读写。

对于缓存读写和直接读写的实现:

Win下面,直接读写走的是Windows Native AIO这条路,缓存读写就是没用使用Simulated AIOWindows Native AIO的线程和数据结构,直接调用读写函数。

Linux下面,直接读写走的是Linux Native AIO这条路,缓存读写走的是缓存读写这条路。

 

1.1.1.1   mysql中的flush

 

write操作后,我们还调用了fdatasync来确保文件数据flush到了disk上。fdatasync返回成功后,那么可以认为数据已经写到了磁盘上。像这样的flush的函数还有fsyncsyncSync函数表示将文件在OS cache中的数据排入写队列,并不确认是否真的写磁盘了,所以sync并不可以靠。fsync函数只对由文件描述符filedes指定的单一文件起作用,并且等待写磁盘操作结束,然后返回。fsync可用于数据库这样的应用程序,这种应用程序需要确保将修改过的块立即写到磁盘上。fdatasync函数类似于fsync,但它只影响文件的数据部分。而除数据外,fsync还会同步更新文件的属性。这里需要特别说明一下的是目前glibcfdatasync函数的实现已经和fsync一摸一样。

忽略文件打开的过程,通常我们会说“写文件”有两个阶段,一个是调用write我们称为写数据阶段(其实是受open的参数影响),调用fsync(或者fdatasync)我们称为flush阶段。对于日志文件的flush主要由下面的系统参数决定。

 

参数Innodb_flush_method(Linux)可以设定为:FdatasyncO_DSYNCO_DIRECT。我们看看这个三个参数是如何影响程序MySQL对日志和数据文件的操作:

 

Open log

Flush log

Open datafile

Flush data

Fdatasync

O_RDWR

fsync()

O_RDWR

fsync()

O_DSYNC

O_RDWR|O_SYNC

 

O_RDWR

fsync()

O_DIRECT

 

fsync()

O_DIRECT

fsync()

 

参数Innodb_flush_method(Win)可以设定为:normalasync_unbuffered我们看看这个二个参数是如何影响程序MySQL对日志和数据文件的操作:

 

Open log

Flush log

Open datafile

Flush data

normal

 

FlushFileBuffers()

 

FlushFileBuffers()

async_unbuffered

FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING

FlushFileBuffers()

FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING

FlushFileBuffers()

 

对于mysql中的日志,flush的时机还由参数innodb_flush_log_at_trx_commit决定

1(默认)

在事务commit时,把日志write进硬盘,之后flush

0

1秒种,把日志write进硬盘,之后flush;事务commit时,无操作

2

在事务commit时,把日志write进硬盘,不flush;每隔1秒,进行flush

默认1是能保证数据库的ACID属性的。当为其它值时,能提高数据库的性能。

 

除上文档上面介绍的,对于日志,通过查看源代码,发现在Simulated AIO或是Native AIO这种写操作结束之后,在write waiter这种线程中,每一次写操作完成时,也会调用flush。具体看下面代码。

if (srv_unix_file_flush_method !=SRV_UNIX_O_DSYNC

         && srv_unix_file_flush_method !=SRV_UNIX_NOSYNC

         && srv_flush_log_at_trx_commit != 2) {

 

         fil_flush(group->space_id);

}

 

 

在Linux下面,同步IO和异步IO与文件是否带缓存没有直接关系,  对于打开的文件,支持缓存读写和直接读写。

对于日志文件,在事务start和commit时,是用带缓存的同步IO写入的,在check point时,用的是带缓存的异步IO写入

对于数据文件,在double write buffer时,是采用带缓存的同步IO写入,在普通的表写入时,是采用不带缓存的异步IO写入

在win下面,由于不支持同一个文件,既带缓存读写,又不带缓存读写,按默认的配置,是根据操作系统的版本,采用对数据文件和日志文件都是异步不带缓存的读写,日志文件在写完后,有一个wait的操作,等待写操作返回。

 

 

对于flush,

在linux下面,日志文件有带缓存的同步写,所以在事务commit和每次写操作完成后都有flush.对于数据文件,是在master thread里面每隔10秒,在把脏页面向硬盘写时完成的,此时先有double buffer write

对于Win下面,采用异步不带缓存的写,但是也有flush,

 

 

 

 

原创粉丝点击