Безопасная запись и чтение из одного файла с несколькими процессами в Linux и Mac OS X
У меня есть три процесса, предназначенных для постоянной работы в среде Linux и Mac OS X. Один процесс (загрузчик) загружает и сохраняет локальную копию большого файла XML каждые 30 секунд. Два других процесса (рабочие) используют сохраненный файл XML для ввода. Каждый работник запускается и работает в случайное время. Поскольку файл XML большой, его загрузка занимает много времени. Рабочие также долго читают и разбирают его.
Какой самый безопасный способ настроить процессы, чтобы Загрузчик не загромождал сохраненный файл, пока Рабочие пытаются его прочитать?
1 ответ
На машинах Linux и Mac OS X, которые используют файловые системы на основе inode, используйте временные файлы для хранения данных во время их загрузки (и они находятся в неполном состоянии). После завершения загрузки переместите временный файл в его окончательное местоположение с атомарным действием.
Чуть более подробно, есть две основные вещи, на которые нужно обратить внимание, когда один процесс (например, Downloader) записывает файл, который активно читается другими процессами (например, рабочими):
- Убедитесь, что работники не пытаются прочитать файл до того, как загрузчик завершит его запись.
- Убедитесь, что загрузчик не изменяет файл, пока его читают рабочие.
Использование временных файлов учитывает оба эти момента.
В качестве более конкретного примера, когда загрузчик активно извлекает файл 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-накопителем), этот метод не будет работать.