Безопасная запись и чтение из одного файла с несколькими процессами в Linux и Mac OS X

У меня есть три процесса, предназначенных для постоянной работы в среде Linux и Mac OS X. Один процесс (загрузчик) загружает и сохраняет локальную копию большого файла XML каждые 30 секунд. Два других процесса (рабочие) используют сохраненный файл XML для ввода. Каждый работник запускается и работает в случайное время. Поскольку файл XML большой, его загрузка занимает много времени. Рабочие также долго читают и разбирают его.

Какой самый безопасный способ настроить процессы, чтобы Загрузчик не загромождал сохраненный файл, пока Рабочие пытаются его прочитать?

1 ответ

Решение

На машинах Linux и Mac OS X, которые используют файловые системы на основе inode, используйте временные файлы для хранения данных во время их загрузки (и они находятся в неполном состоянии). После завершения загрузки переместите временный файл в его окончательное местоположение с атомарным действием.

Чуть более подробно, есть две основные вещи, на которые нужно обратить внимание, когда один процесс (например, Downloader) записывает файл, который активно читается другими процессами (например, рабочими):

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

Использование временных файлов учитывает оба эти момента.

В качестве более конкретного примера, когда загрузчик активно извлекает файл XML, он должен выполнить запись во временную папку (например, "data-storage.tmp") на том же устройстве / диске *, где будет храниться конечный файл. После того, как файл полностью загружен и записан, загрузчик должен переместить его в конечное местоположение (например, "data-storage.xml") с помощью атомарной (иначе называемой линеаризуемой) команды переименования, такой как bash mv,

* Обратите внимание, что причина, по которой временный файл должен находиться на том же устройстве, что и конечное местоположение файла, состоит в том, чтобы гарантировать, что номер индекса сохраняется, а переименование может быть выполнено атомарно.

Эта методология гарантирует, что во время загрузки / записи файла рабочие не увидят его, поскольку он находится в папке.tmp. Из-за того, как переименование работает с inode, он также гарантирует, что любой Worker, открывший файл, продолжит видеть старое содержимое, даже если будет установлена ​​новая версия файла хранилища данных.

Загрузчик будет указывать "data-storage.xml" на новый номер инода, когда он будет переименовывать, но рабочий продолжит обращаться к "data-storage.xml" с предыдущего номера инода, тем самым продолжая работать с файлом в этом состоянии, В то же время любой работник, открывающий новую копию "data-storage.xml" после того, как Downloader выполнил переименование, будет видеть содержимое из нового номера индекса, поскольку теперь это то, на что ссылается непосредственно в файловой системе. Таким образом, два Рабочих могут читать с одного и того же имени файла (data-storage.xml), но каждый увидит свою (и полную) версию содержимого файла, в зависимости от того, на какой индекс указывалось имя файла при первом открытии файла.,

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


Важным примечанием является то, что файловая система на конкретном устройстве имеет значение. Если вы используете компьютер с Linux или Mac, но работаете с файловой системой FAT (например, с USB-накопителем), этот метод не будет работать.

Другие вопросы по тегам