2016-08-16 4 views
1

В моем веб-приложении Java используется файловая система NFS, я использую FileOutputStream для открытия, записи нескольких фрагментов и последующего закрытия файла.Почему java FileOutputStream пишет() или flush() не делает NFS-клиент действительно отправлять данные на сервер NFS?

Из статистики профилировщика я обнаружил, что stream.write (байт [] полезная нагрузка, int begin, int length) и даже stream.flush() принимает нулевые миллисекунды. Только метод call stream.close() принимает ненулевые миллисекунды.

Кажется, что java FileOutputStream write() или flush() на самом деле не заставляет клиента NFS отправлять данные на сервер NFS. Есть ли какой-либо другой Java-класс, который сделает данные NFS для клиента в реальном времени? или необходимо выполнить настройку клиента NFS?

ответ

1

Возможно, вы работаете в кешировании на стороне клиента Unix. Есть много деталей here in the O'Reilly NFS book.

Но короче:

Использование кэш буфера и позволяя асинхронных потоков для кластера нескольких буферов представляет некоторые проблемы, когда несколько машин для чтения и записи в тот же файл. Чтобы предотвратить несогласованность файлов с несколькими читателями и писателями одного и того же файла, NFS вводит политику flush-on-close: Все частично заполненные буферы данных NFS для файла записываются на сервер NFS, когда файл закрыт.

Для клиентов NFS версии 3 любые записи, сделанные с установленным выключенным флагом стабилизации, принудительно переходят в стабильное хранилище сервера посредством операции фиксации.

NFS целостность кэш использует подход, называемый близко к открытой консистенции кэша - то есть, вы должны закрыть файл до вашего сервера (и других клиентов) получают непротиворечивое представление уточненных из файл. Вы видите недостатки этого подхода, целью которого является минимизация ударов серверов.

Избежать кеша трудно из Java. Вам нужно установить флаг open()O_DIRECT, если вы используете Linux; см. этот ответ для более 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 ...

В качестве альтернативы, если у вас есть контроль над точкой подключения клиента, вы можете использовать опцию монтирования sync в соответствии с NFS manual. Он говорит:

Если опция синхронизации указана на точку монтирования, любой системный вызов , который записывает данные в файлы на этом точку монтирования вызывает то, что данные были сбрасываться на сервере до возвращения системного вызова управления для пользователь место. Это обеспечивает большую согласованность кэширования данных среди клиентов, но при значительной стоимости исполнения.

Это может быть то, что вы ищете.

+0

Я использую клиент NFS версии 3, можно ли установить параметр монтирования для принудительного сброса на сервер? – user1532146

+0

@ user1532146 попробуйте опцию 'sync' mount. Проверьте здесь: http://man7.org/linux/man-pages/man5/nfs.5.html, я обновлю ответ. Немного нервничал, потому что я не пробовал ... (и я отчаянно пытаюсь выяснить, является ли это NFSv3 или v4!) – SusanW

+0

@ user1532146 нормально, поддерживается в v3. – SusanW

-2

Как правило, потоки Java не дают никаких гарантий относительно эффектов flush, кроме, может быть, промывки буферов в Java-классах.

Чтобы преодолеть это ограничение, можно использовать каналы Java NIO, например, https://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileChannel.html#force(boolean). Однако, если «файл не находится на локальном устройстве, такая гарантия не предоставляется». И Java не может сделать такую ​​гарантию, потому что базовая удаленная файловая система или протокол может вообще не предоставлять эту функцию. Тем не менее, вы должны иметь возможность добиться почти одинакового уровня синхронизации с force(), который вы получили бы от родного O_DIRECT доступа, упомянутого в @SusanW.

+0

Так что до сих пор нет гарантии. Трудно видеть точку ответа. – EJP

+0

IMHO, он отлично отвечает на вопрос «Почему java FileOutputStream [...] flush() не [...] действительно отправляет данные на сервер NFS?» Трудно понять, почему кто-нибудь, кроме @EJP, будет downvote. – JimmyB

+0

Он не отвечает на вопрос о '' FileOutputStream'' .write() 'или *' flush() 'каким-либо образом и не дает решения проблемы, потому что проблема не в том, что Java, это с NFS. И утверждение о 'flush()', не предоставляющем никаких гарантий, просто неверно. 'FileOutputStream.flush()' специально документируется через наследование, чтобы ничего не делать. – EJP