2008-10-20 5 views
5

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

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

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

Любые лучшие идеи?

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

ответ

2

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

Edit: от flock() страницы:

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

Edit 2:

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

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

+0

На данный момент это будет хорошо, но как только это закончится разработкой, оно будет развернуто на нескольких виртуальных серверах для балансировки нагрузки, и это запустит гаечный ключ [buther] в работах. – Oli 2008-10-20 13:43:57

3

Один из подходов может заключаться в создании экземпляра Memcache, который используется совместно с каждым из ваших виртуальных серверов. Вы могли бы apes 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); 
} 

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

0

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

if ($memcache->add($filename, 1, 1)) 
{ 
    $memcache->delete($filename); 
} 
1

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

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

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

14

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

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

  • символических ссылок
  • переименовывать

С NFSv3 вызов создать также атомный.

Зная это, вы можете реализовать спин-блокировки для файлов и каталогов (в оболочке, а не 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 

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

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

+0

Эти комментарии на странице руководства flock связаны, и я нашел их весьма полезными. http://www.php.net/manual/en/function.flock.php#46085 http://www.php.net/manual/en/function.flock.php#68875 HTTP: //www.php.net/manual/en/function.flock.php#82521 – aiham 2011-03-31 03:03:20

2

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

Смежные вопросы