Linux I/O系列之直接内存(Direct IO)原理剖析和使用

2,044

这是我参与8月更文挑战的第29天,活动详情查看:8月更文挑战

一、前言

在上一篇文章《Linux I/O操作fsync后数据就安全了么(fsync、fwrite、fflush、mmap、write barriers详解)》中咱们一起学习了在Linux中如何将数据安全的写入到磁盘。其中我们提到了直接IO。使用它能够在磁盘缓存空间和用户空间直接建立一个通道,这样咱们在用户空间就能够直接操作磁盘中的数据。

本文咱们就一起深入学习直接IO,在开始之前大家可以先思考下面几个问题,看看自己是否都能够正确解答。

1、什么是直接IO?

2、什么场景下可以使用直接IO?

3、为什么我们需要使用直接IO?

4、直接IO的优缺点是什么?

5、直接IO中,应用Buffer和磁盘之间到底有没有缓存?

二、直接IO

1、什么是直接IO

直白点的解释:直接IO就是在应用层Buffer和磁盘之间直接建立通道。这样在读写数据的时候就能够减少上下文切换次数,同时也能够减少数据拷贝次数,从而提高效率。

官方解释如下:主要关注如下两点,

a、在应用层和磁盘之间的通道并不是没有缓存,只是缓存很小。

b、直接IO并不能保证O_SYNC特性。

2、如何使用直接IO

直接IO的使用很简单,只需要在open文件的时候添加O_DIRECT标识即可。但是咱们的Java本身并不支持直接IO。如果Java程序想要使用直接IO则需要引用JNA包,通过直接调用Linux底层指令来操作文件,在打开文件(open)的时候自己指定O_DIRECT标识。直接IO在Ignite中使用的比较好,大家可以参考他的具体代码示例使用例子(搜索ignite官方下载代码即可)。具体代码在ignite-direct-io包中。

3、使用直接IO的注意事项

通常直接IO的使用都会导致性能下降。因为数据几乎没有被内核缓存,所有的读写操作都是直接对磁盘中的文件进行操作。所以使用的时候需要在应用层做好缓存,合理进行读写操作,否则会导致性能急剧下降。

另外使用直接IO需要基于块的维度读写数据,即数据的读写需要是设备的块大小和linux系统的页大小的整数倍。所以通常我们都以4K大小的块读写数据。

4、直接IO的优缺点

A、优点

a、应用层直接操作磁盘减少了上下文切换和数据拷贝的开销,速度更快。

b、数据直接缓存在应用层,应用能够更加灵活的操作数据。

B、缺点

a、系统基本不缓存数据,因此应用需要合理的读写数据,否则会导致性能很差。

b、所有缓存都由应用层直接控制,增加了应用层的实现复杂度,对开发者能力要求很高。

c、O_DIRECT也不能确保数据每次写入的时候同步写入磁盘,因此如果需要数据同步写入磁盘还需要手工设置O_SYNC标识或者手工调用fsync方法。

5、问题解答

对直接IO的学习就到这里,最后我们来一一解答之前咱们提出的问题。

1、什么是直接IO?

正文已解答。

2、什么场景下可以使用直接IO?

通常需要自己控制所有数据的缓存,想要更加灵活自如的输出文件数据。如数据库、同步日志系统等。

3、为什么我们需要使用直接IO?

参考其优点。

4、直接IO的优缺点是什么?

正文已解答。

5、直接IO中,应用Buffer和磁盘之间到底有没有缓存?

有缓存,只是很小。

最后给大家留一个问题:既然直接IO在引用Buffer和磁盘之间有缓存,那这个缓存在哪个位置呢?C标准库Buffer?内核的Page Cache?

三、惯例

如果你喜欢本文或觉得本文对你有所帮助,欢迎一键三连支持,非常感谢。

如果你对本文有任何疑问或者高见,欢迎添加公众号lifeofcoder共同交流探讨。