回忆一下
我们都知道Linux的IO模型有阻塞、非阻塞、SIGIO、多路复用(select,epoll)、AIO(异步I/O)等。
数据库可能比较倾向于使用AIO。从时序上面来讲,AIO是用户应用发起IO请求io_submit()后,它就不需要去等待,让后台给它搞定读写。之后本线程或者其他线程就可以通过io_getevents()去同步I/O的结果。
这样的AIO有一个极大的好处在于,IO不会阻塞住CPU的行为,有利于充分利用硬件的资源,有利于让CPU、IO都parallel起来 。当然,同样的动作,似乎用epoll()、SIGIO也可以呈现出来。尤其是epoll(),几乎是C10K问题解决方案在Linux的代名词。epoll_wait()先等待IO请求的read、write可以发生,而后再根据返回的事件发起读写请求:
事件驱动模型libevent等,看起来是事件到来,callback被执行的Reactor模式:
但是其底层其实也是靠epoll()来实现,这个我们透过strace就可以看出。请见我的3分钟小电影:
大不一样
epoll()本质上其实还是先等待IO的读写可以发生,而后再以Linux常规read()、write() API去发起IO请求。而AIO则是不管三七二十一,直接发IO请求,但是并不等待这个请求的结束,让Linux后台自己去完成读写。我们来看一个典型的AIO编程案例:
它是通过io_submit()把IO请求发出去之后,它并不需要等IO的结束。后面用io_getevents()去同步。上面的代码中,io_getevents()的代码与io_submit()的代码摆在一起,但是其实它们并不需要一定是同一个线程。
AIO和传统epoll()的本质区别是,epoll()等方式,它只是一个事件获取机制,获取事件后,之后的read(), write()还是要走Linux的传统路线,经过Linux内核本身的各个层次(如page cache,IO调度等)。而AIO是骨子里面,自己就是一个IO的方式,最终没有经过传统的Linux read(),write()这种"all is file"的类VFS接口。Linux native的AIO本身call的函数,本身就是系统调用。strace执行AIO动作的进程得到的直接就是类似如下的结果:
strace ./aio....
...
io_setup(128, {3077799936}) = 0
io_submit(3077799936, 1, 0xbfa5e730) = 1
io_getevents(-1217167360, 1, 1, {...}NULL) = 1
在ARM Linux的系统调用表里也可以看出:
故而,AIO可以更多地把机会交给用户空间,让用户空间根据自身的IO特点来为自己量身定制IO的行为。AIO一般也直接结合DIO(direct IO)来使用,进一步绕开内核本身的IO调度和cache机制。
我中意你
那么AIO有什么可能的优势被数据库所青睐呢?
1. 透过AIO,可以屏蔽掉Linux内核底层的page cache。而制定application-level的cache机制。
我们都知道,Linux会针对每个文件对应的inode,创立一个address_space,并以Radix树来组织它的page cache命中情况,page的替换算法,整体是LRU,预测页面本身的活跃度。这个策略,固然非常符合局部性原理(Locality),但是不能针对用户程序本身的特征,进行用户级的cache。
2.透过AIO(尤其是结合DIO),可以一定程度上,进行用户级别的IO scheduling。采用AIO,用户可以控制发送给内核的IO请求,从而控制谁比谁更重要。内核固然有它的IO调度算法,但是它是比较general的。
3. 透过AIO,可以进行用户级别的read-ahead和write-behind控制。
我们都知道,Linux内核本身会根据用户的读请求,去预测后续的读,从而在后续的读还没有发起的情况下,就提前预读。详见:《宋宝华: 文件读写(BIO)波澜壮阔的一生》,但是这种预读的page,并不一定是上层应用想要的page。而内核的write-behind机制,也可能导致内核累积到很多dirty数据后,出现写磁盘的突发性洪泛。现在AIO机制,我们把这些都交给用户。
4. 透过AIO,不阻塞地在前台线程,直接dispatch IO请求,带来很好的
scalability。在InnoDB里面,可以透过innodb_use_native_aio来配置使用同步的IO还是AIO,而且它有一番对比,值得细细地品读。同步IO的时候,query threads是将IO请求放入queue,由InnoDB后台线程的每个线程处理一个IO请求。而AIO的时候,query threads直接发IO请求。
With synchronous I/O, query threads queue I/O requests, andInnoDBbackground threads retrieve the queued requests one at a time, issuing a synchronous I/O call for each. When an I/O request is completed and the I/O call returns, the InnoDBbackground thread that is handling the request calls an I/O completion routine and returns to process the next request. The number of requests that can be processed in parallel isn, wherenis the number ofInnoDBbackground threads. The number ofInnoDBbackground threads is controlled byinnodb_read_io_threadsand innodb_write_io_threads.
With native AIO, query threads dispatch I/O requests directly to the operating system, thereby removing the limit imposed by the number of background threads.InnoDBbackground threads wait for I/O events to signal completed requests. When a request is completed, a background thread calls an I/O completion routine and resumes waiting for I/O events.
-
cpu
+关注
关注
68文章
10831浏览量
211215 -
Linux
+关注
关注
87文章
11233浏览量
208973 -
数据库
+关注
关注
7文章
3769浏览量
64291
原文标题:今年是“异型屏”转换年!华映看好手机市场Q4复苏
文章出处:【微信号:zengshouji,微信公众号:MCA手机联盟】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论