Linux I/O系列:不使用fsync如何尽快将数据写入磁盘(posix_fadivce的作用与实际应用)

969 阅读3分钟

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

一、前言

通过前面一系列的文章我们学习了《Linux I/O操作fsync后数据就安全了么(fsync、fwrite、fflush、mmap、write barriers详解)》和《Linux I/O系列之直接内存(Direct IO)原理剖析和使用》,通过前面的学习我想大家都应该知道咱们在开发过程中怎样才能够将数据安全地写入磁盘了。那么提到数据安全写入磁盘我们首先会想到使用fsync或者O_SYNC标识。但是如果我们不用fsync或者O_SYNC标识呢,咱们有没有什么办法能够让内核尽快将数据从Page Cache写入磁盘呢?当然有,接下来我们就和大家一起学习posix_fadvise函数。

二、posix_fadvise函数

1、定义

我们直接看官方介绍可知:其作用是设置一个意图来告诉内核该文件数据在未来会怎样,从而让内核能够对数据进行一定的优化。

man7.org/linux/man-p…

2、advice参数

其重要的就是advice参数,我们给文件fd设置不同的advice参数,Linux内核就能够做出对应的优化。

POSIX_FADV_NORMAL

表示该应用程序没有建议提供有关其指定的数据访问模式。如果没有意见,给出了一个打开的文件,这是默认的假设。

POSIX_FADV_SEQUENTIAL

该应用程序需要访问指定的数据顺序(与以前高的人读低偏移)。

POSIX_FADV_RANDOM

将指定的数据将会以随机顺序进行访问。

POSIX_FADV_NOREUSE

将指定的数据将只访问一次。

POSIX_FADV_WILLNEED

将指定的数据将在不久的将来访问。

POSIX_FADV_DONTNEED

指定的数据不会在短期内被访问。

3、使用方法

如果是C语言直接使用就比较简单,参考官方说明文档即可。

如果是在Java中使用,相对就比较复杂一点。因为Java本身并不支持,所以我们需要额外引入JNA包,通过直接调用底层C函数实现。具体可以参考Ingite的ignite-direct-io包中对posix_fadvice的使用

三、posix_fadvise的应用场景

在实际开发中我们有什么场景需要使用到posix_fadvise呢?在上一篇文章《Linux I/O系列之直接内存(Direct IO)原理剖析和使用》中,我们学习了Linux中直接内存的使用。其中我们提到了直接内存在内核中也有缓存,只是缓存很少。那么如果我们不主动使用fsync或者O_SYNC同步数据到磁盘,此时我们就可以通过posix_fadvise函数设置POSIX_FADV_DONTNEED来告诉内核这个数据我们后续不再使用了。这样内核就能再下次扫描Page Cache的时候尽可能地将数据从内核中清除,并将数据同步到磁盘中。这样就能够经历确保直接内存的缓存数据近实时落盘。

注意上面提到的是内核会尽力去做落盘操作,但是它并没有保证下次扫描就一定会落盘哦。

所以POSIX_FADV_DONTNEED参数就是我们本文介绍的重点,我们可以通过给文件数据设置该属性,让内核能够尽力的将数据从内核缓存中清除,并写入磁盘。因此如果我们的业务场景能接受数据近同步落盘,那么我们就可以使用POSIX_FADV_DONTNEED参数,而不用每次写数据后都手动执行fsync。很明显使用POSIX_FADV_DONTNEED参数的性能比每次写数据都手动调用fsync要高很多。

学习完posix_fadvise函数后,本文开头提到的问题也就很容易解答了。

四、惯例

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

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