Блокировка файлов NFS в PHP - PullRequest
       14

Блокировка файлов NFS в PHP

7 голосов
/ 20 октября 2008

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

flock(...) обычно превосходно, но, похоже, не работает на NFS ... Что для меня является огромной проблемой, поскольку рабочий сервер использует массив NFS.

Самое близкое, что я видел в реальном решении, это попытка создать каталог блокировки и ожидание, пока он не будет создан. Сказать, что этому не хватает элегантности, значит преуменьшение года, возможно десятилетия.

Есть идеи получше?

Редактировать: Я должен добавить, что у меня нет root на сервере, и что в ближайшее время не удастся сделать хранилище другим способом, не в последнюю очередь в мой срок.

Ответы [ 6 ]

16 голосов
/ 09 ноября 2008

Операции с каталогами НЕ атомарные в NFSv2 и NFSv3 (пожалуйста, обратитесь к книге «NFS Illustrated» Брента Каллагана, ISBN 0-201-32570-5; Брент - ветеран NFS на Солнце).

NFSv2 имеет две атомарные операции:

  • символическая
  • переименование

В NFSv3 вызов create также является атомарным.

Зная это, вы можете реализовать спин-блокировки для файлов и каталоги (в оболочке, а не в PHP):

блокировка текущего каталога:

while ! ln -s . lock; do :; done

заблокировать файл:

while ! ln -s ${f} ${f}.lock; do :; done 

разблокировка (при условии, что запущенный процесс действительно получил блокировку):

разблокировать текущий каталог:

mv lock deleteme && rm deleteme

разблокировать файл:

mv ${f}.lock ${f}.deleteme && rm ${f}.deleteme

Удалить тоже не атомарно, поэтому сначала переименуем (которое атомарный), а затем удалить.

Для вызовов символической ссылки и переименования оба имени файла должны находиться на та же файловая система. Мое предложение: использовать только простые имена файлов и поставить файл и заблокировать в том же каталоге.

3 голосов
/ 20 октября 2008

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

Каждый сервер может получить доступ к этому пулу перед файловой операцией и посмотреть, присутствует ли эта «блокировка», например,

// Check for lock, using $filename as key
$lock = $memcache->get($filename);

if(!$lock) {
    // Set lock in memcache for $filename
    $memcache->set($filename, 1);

    // Do file operations...

    // Blow away "lock"
    $memcache->delete($filename);
}

Не самое элегантное решение, но оно должно позволять вам с относительной легкостью управлять блокировками со всех серверов в вашей настройке.

2 голосов
/ 21 мая 2010

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

2 голосов
/ 20 октября 2008

Другим грязным хаком было бы flock() «локальный» файл, и открывать / записывать в файл NFS только если вы удерживаете блокировку локального файла.

Редактировать: со страницы flock():

flock () не будет работать на NFS и многих другие сетевые файловые системы. Проверьте документация вашей операционной системы для более подробной информации.

Редактировать 2:

Конечно, всегда есть база данных для синхронизации доступа (я предполагаю, что ваше приложение использует БД). Хотя это может сильно повлиять на производительность, если вы ведете много журналов.

Если это просто для регистрации, вам действительно нужен централизованный файл журнала? Можете ли вы войти локально (и даже объединить журналы, когда они вращаются в конце дня, если это необходимо)?

1 голос
/ 20 октября 2008

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

Чтобы реализовать собственную функцию блокировки NFS, проверьте или создайте каталог, если вы хотите заблокировать его, и удалите его, когда закончите.

К сожалению, он, вероятно, не совместим с любым другим приложением, которое вы не написали сами.

0 голосов
/ 20 октября 2008

Нужно просто использовать memcache add и избегать условия гонки.

if ($memcache->add($filename, 1, 1))
{
   $memcache->delete($filename);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...