我的Java Web应用程序使用NFS文件系统,我使用FileOutputStream打开,写入多个块然后关闭文件。
从分析器统计信息中我发现stream.write(byte [] payload,int begin,int length)甚至stream.flush()需要零毫秒。只有方法调用stream.close()才需要非零毫秒。
java FileOutputStream的write()或flush()似乎并没有真正导致NFS客户端向NFS服务器发送数据。是否还有其他Java类会使NFS客户端实时刷新数据?或者需要进行一些NFS客户端调优?
答案 0 :(得分:1)
您可能正在进行Unix客户端缓存。有很多细节here in the O'Reilly NFS book。
但简而言之:
当多台计算机正在读取和写入同一文件时,使用缓冲区缓存并允许异步线程集群多个缓冲区会引入一些问题。为防止文件与同一文件的多个读取器和编写器不一致,NFS建立了一个关闭冲洗策略: 当文件关闭时,文件的所有部分填充的NFS数据缓冲区都将写入NFS服务器。
对于NFS版本3客户端,任何将设置为关闭的稳定标志的写入都会通过提交操作强制进入服务器的稳定存储。
NFS缓存一致性使用称为接近开放缓存一致性的方法 - 也就是说,您必须在服务器(和其他客户端)获得一致的最新信息之前关闭该文件文件的视图。您正在看到此方法的缺点,旨在最大限度地减少服务器命中。
从Java中避免缓存很难。如果您正在使用Linux,则需要设置文件open()
O_DIRECT
标记;请参阅此答案以获取更多https://stackoverflow.com/a/16259319/5851520,但基本上它会禁用该文件的客户端操作系统缓存,但不会禁用服务器。
不幸的是,标准JDK没有公开O_DIRECT
。正如这里所讨论的那样:Force JVM to do all IO without page cache (e.g. O_DIRECT) - 基本上,你自己使用JNI或使用一个不错的第三方库。我听说过JNA的好消息:https://github.com/java-native-access/jna ......
或者,如果您可以控制客户端挂载点,则可以按NFS manual使用sync
挂载选项。它说:
如果在安装点上指定了同步选项,则进行任何系统调用 将数据写入该挂载点上的文件会导致该数据 在系统调用将控制权返回给用户之前刷新到服务器 空间。这提供了客户端之间更高的数据缓存一致性,但是 以显着的性能成本。
这可能是您正在寻找的。 p>
答案 1 :(得分:-2)
一般来说,Java的流不能保证flush
的影响,除了可能在所涉及的Java类中刷新缓冲区。
为了克服这个限制,可以使用Java NIO的频道,例如https://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileChannel.html#force(boolean)。但是,如果"该文件不驻留在本地设备上,则不会进行此类保证。"并且Java无法做出这样的保证,因为底层远程文件系统或协议可能根本无法提供该功能。但是,您应该能够(@几乎)与force()
实现同步级别的同步,而这与@SusanW提到的本地O_DIRECT
访问权限相同。