Особые соображения при выполнении файлового ввода-вывода в общем ресурсе NFS через демон на основе Python?

У меня есть демон на основе Python, который предоставляет REST-подобный интерфейс через HTTP для некоторых инструментов командной строки . Общая природа инструмента состоит в том, чтобы принять запрос, выполнить какое-либо действие командной строки, сохранить структурированную структуру данных на диск и вернуть некоторые данные вызывающей стороне. При запуске демона создается вторичный поток, который периодически просматривает эти обработанные данные на диске и выполняет некоторую очистку на основе того, что содержится в данных.

Это прекрасно работает, если диск, на котором находятся обработанные данные, является локальным диском на машине с Linux. Если вы переключаетесь на диск, смонтированный по NFS, демон начинает свою жизнь нормально, но со временем общий ресурс, смонтированный по NFS, «исчезает», и демон больше не может определить, где он находится на диске, с помощью вызовов типа os.getcwd(). Вы начнете видеть, что он регистрирует такие ошибки, как:

2011-07-13 09:19:36,238 INFO Retrieved submit directory '/tech/condor_logs/submit'
2011-07-13 09:19:36,239 DEBUG CondorAgent.post_submit.do_submit(): handler.path: /condor/submit?queue=Q2%40scheduler
2011-07-13 09:19:36,239 DEBUG CondorAgent.post_submit.do_submit(): submitting from temporary submission directory '/tech/condor_logs/submit/tmpoF8YXk'
2011-07-13 09:19:36,240 ERROR Caught un-handled exception: [Errno 2] No such file or directory
2011-07-13 09:19:36,241 INFO submitter - - [13/Jul/2011 09:19:36] "POST /condor/submit?queue=Q2%40scheduler HTTP/1.1" 500 -

Необработанное исключение разрешается тем, что демон больше не может видеть диск. Любые попытки определить текущий рабочий каталог демона с помощью os.getcwd() на этом этапе потерпят неудачу. Даже попытка перейти в корень монтирования NFS /tech потерпит неудачу. Все это время методы logger.logging.* радостно записывают журналы и отладочные сообщения в файл журнала, расположенный на общем ресурсе, подключенном к NFS, по адресу /tech/condor_logs/logs/CondorAgentLog.

Диск определенно все еще доступен. Существуют и другие демоны на основе C++, выполняющие чтение и запись с гораздо более высокой частотой в этом общем ресурсе по сравнению с демоном на основе python.

Я зашел в тупик, решая эту проблему. Поскольку он работает на локальном диске, общая структура кода должна быть хорошей, верно? Что-то несовместимо с общими ресурсами NFS и моим кодом, но я не могу сказать, что это может быть.

Есть ли какие-то особые соображения, которые необходимо учитывать при работе с демоном Python, работающим в течение длительного времени, который будет часто выполнять чтение и запись в общий файловый ресурс, подключенный к NFS?


Если кто-то хочет увидеть код, часть, которая обрабатывает HTTP-запрос и записывает маринованный объект на диск, находится в github здесь. И часть, которую подпоток использует для периодической очистки данных с диска путем чтения маринованных объектов, — это здесь.


person Ian C.    schedule 16.08.2011    source источник


Ответы (2)


У меня есть ответ на мою проблему, и он не имеет никакого отношения к тому факту, что я выполнял файловый ввод-вывод на общем ресурсе NFS. Оказывается, проблема просто проявлялась быстрее, если ввод-вывод выполнялся через монтирование NFS, а не через локальный диск.

Ключевым моментом информации является то, что код выполнялся в потоке через классы SocketServer.ThreadingMixIn и HTTPServer.

Мой код обработчика делал что-то близкое к следующему:

base_dir = getBaseDirFromConfigFile()
current_dir = os.getcwd()
temporary_dir = tempfile.mkdtemp(dir=base_dir)
chdir(temporary_dir)
doSomething()
chdir(current_dir)
cleanUp(temporary_dir)

Это поток, более или менее.

Проблема заключалась не в том, что ввод-вывод выполнялся в NFS. Проблема заключалась в том, что os.getcwd() не является локальным потоком, это глобальный процесс. Так как один поток выдал chdir() для перемещения во временное пространство, которое он только что создал под base_dir, следующий поток, вызывающий os.getcwd(), получит temporary_dir другого потока вместо статического базового каталога, в котором был запущен HTTP-сервер.

Есть и другие люди, сообщающие о подобных проблемах здесь и здесь.

Решение состояло в том, чтобы избавиться от вызовов chdir() и getcwd(). Для запуска и пребывания в одном каталоге и доступа ко всему остальному через абсолютные пути.

Сравнение NFS и локальных файлов через меня в цикле. Получается мой блок:

chdir(temporary_dir)
doSomething()
chdir(current_dir)
cleanUp(temporary_dir)

работал намного медленнее, когда файловая система была NFS, чем локальная. Это привело к тому, что проблема возникла намного раньше, потому что это увеличило вероятность того, что один поток все еще находится в doSomething(), в то время как другой поток выполняет часть current_dir = os.getcwd() блока кода. На локальном диске потоки перемещались по всему блоку кода так быстро, что редко пересекались подобным образом. Но дайте ему достаточно времени (около недели), и проблема возникнет при использовании локального диска.

Итак, большой урок, полученный при работе с потокобезопасными операциями в Python!

person Ian C.    schedule 08.09.2011

Буквально отвечая на вопрос, да, с NFS есть некоторые проблемы. Например.:

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

  • В частности, вы не можете полагаться на O_APPEND для атомарного добавления к файлам.

  • В зависимости от сервера NFS, O_CREAT|O_EXCL может работать некорректно (по крайней мере, в современных Linux он работает правильно).

  • Особенно старые серверы NFS имеют недостаточную или полностью неработающую поддержку блокировки. Даже на более современных серверах восстановление блокировки может стать проблемой после перезагрузки сервера и/или клиента. NFSv4, протокол с отслеживанием состояния, здесь должен быть более надежным, чем старые версии протокола.

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

person janneb    schedule 16.08.2011
comment
Пространство кэша находится за пределами области очистки Condor, поэтому это определенно не случай удаления данных. В этом можно убедиться, взглянув на акцию: все правильно там, где написано. Я не использую блокировку неявно, но мне пришло в голову, что ее можно использовать — я использую «w» и «wb», чтобы открывать дескрипторы файлов для записи с помощью встроенного в Python open(). «р» для чтения. Если что-то не происходит под капотом, я почти уверен, что избегаю ошибок в вашем посте. - person Ian C.; 17.08.2011