блокировка файлов в PHP (тип чтения / записи)

У меня есть сценарий, когда один процесс PHP записывает файл примерно 3 раза в секунду, а затем несколько процессов PHP читают этот файл.

Этот файл по сути является кешем. Наш веб-сайт проводит очень настойчивый опрос данных, которые постоянно меняются, и мы не хотим, чтобы каждый посетитель обращался к БД при каждом опросе, поэтому у нас есть процесс cron, который читает БД 3 раза в секунду, обрабатывает данные, и выводит его в файл, который затем могут прочитать клиенты опроса.

У меня проблема в том, что иногда открытие файла для записи занимает много времени, иногда даже до 2-3 секунд. япри условии, что это происходит потому, что он заблокирован чтением (или чем-то другим), но у меня нет никакого убедительного способа доказать это, плюс, согласно тому, что я понимаю из документации, PHP не должен ничего блокировать. Это происходит каждые 2-5 минут, так что это довольно часто.

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

Я пишу файл с этим кодом:

$handle = fopen(DIR_PUBLIC . 'filename.txt', "w");
fwrite($handle, $data);
fclose($handle);

И я читаю это непосредственно с:

file_get_contents('filename.txt')

(он не передается напрямую клиентам в виде статического файла, я получаю обычный запрос PHP, который читает файл и выполняет с ним некоторые базовые функции)

Размер файла составляет около 11 КБ, поэтому для чтения / записи не требуется много времени. Хорошо под 1 мс.

Это типичная запись в журнале, когда возникает проблема:

  Open File:    2657.27 ms
  Write:    0.05984 ms
  Close:    0.03886 ms

Не уверен, что это уместно, но чтение происходит в обычных веб-запросах через apache, но запись - это обычное PHP-выполнение «командной строки», выполняемое cron Linux, оно не проходит через Apache.

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

В качестве альтернативы, можете ли вы придумать, что я мог бы сделать, чтобы избежать этого? Например, я бы хотел установить тайм-аут на 50 мс для fopen, и если он не откроет файл, он просто пропустит его и позволит следующему запуску cron позаботиться об этом.

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

Спасибо!
Даниил

 Daniel Magliola21 сент. 2010 г., 12:44
Будет ли изменение режима добавления добавить избежать блокировки?
 Mark Baker21 сент. 2010 г., 12:48
Является ли запись в файл с другим именем, а затем переименование в общий файл кэша вариант?
 Daniel Magliola21 сент. 2010 г., 12:54
Марк, я думал об этом, но я боюсь, что удаление файла, которое сейчас занимает много времени, будет так же плохо. Это в моем списке вещей, чтобы попробовать хотя
 halfdan21 сент. 2010 г., 12:41
От того, как реализованы блокировки и зависит ли их PHP, зависит от файловой системы. Если вы открываете файл в режиме чтения, блокировка не должна создаваться. Однако вы можете заменить «w» (запись) на «a» (только добавление)

Ответы на вопрос(2)

Решение Вопроса

файл блокируется при чтении / записи в него низкими системными вызовами php без вашего ведома. Это должно заблокировать файл на 1 / 3с макс. Вы получаете периоды дольше, что это.кеш fs запускает fsync (), и вся система блокирует чтение / запись на диск, пока это не будет сделано. В качестве исправления вы можете попробовать установить больше оперативной памяти, обновить ядро ​​или использовать более быстрый жесткий диск.Ваше решение для «кэширования» не распространяется, и оно многократно врезается в наихудшую часть оборудования во всей системе ... это означает, что вы не можете масштабировать его дальше, просто добавляя больше машин, только увеличивая скорость жесткого диска. Вы должны взглянуть на memcache или APC, или, может быть, даже общую памятьhttp://www.php.net/manual/en/function.shm-put-var.php

Решения, которые я могу придумать:

положить этот файл в ramdiskhttp://www.cyberciti.biz/faq/howto-create-linux-ram-disk-filesystem/ , Это должен быть самый простой способ избежать частого попадания на диск без других серьезных изменений.использовать memcache. Он очень быстрый, когда используется локально, хорошо масштабируется, используется «большими» игроками.http://www.php.net/manual/en/book.memcache.phpиспользовать разделяемую память Он был разработан для того, что вы пытаетесь сделать здесь ... имея «общую зону памяти» ...измените планировщик cron, чтобы он обновлялся меньше, возможно, внедрите какую-то систему событий, чтобы он обновлял кеш только при необходимости, а не по временисделайте так, чтобы «пишущий» скрипт записывал в 3 файла, и «читалок» читал из одного из файлов случайным образом. Это может позволить «распределение» блокировки по большему количеству файлов и может уменьшить вероятность того, что определенный файл заблокирован при записи в него ... но я сомневаюсь, что это принесет какие-либо заметные преимущества.
 Daniel Magliola29 сент. 2010 г., 03:07
Я закончил тем, что выбрал решение ramdisk, которое оказало наименьшее влияние на код, и оно сработало LIKE A CHARM. Огромное спасибо!!
 Quamis21 сент. 2010 г., 15:38
@Daniel: да, он должен работать между процессами, поэтому он был реализован :)
 Daniel Magliola21 сент. 2010 г., 15:06
Я НЕ знал о разделяемой памяти PHP, я думал, что это невозможно с PHP. Это выглядит ОЧЕНЬ интересно, действительно ... Я собираюсь разобраться в этом. Если честно, у меня нет опыта работы с memcached, и я бы хотел избежать установки новой системы, учитывая мой опыт сисадмина. Мы будем, если придется, но сейчас я бы предпочел более простой подход. Большое спасибо!!
 Daniel Magliola21 сент. 2010 г., 15:09
Один вопрос ... Будет ли совместная память PHP работать через процесс cron и процессы Apache PHP? У меня есть процесс cron, который выполняется в течение 5 минут и завершает (и перезагружается cron) запись, а затем PHP-процесс Apache отвечает на запросы HTTP, читая эту общую память. Будет ли это работать правильно?
 Quamis29 сент. 2010 г., 08:16
Рад, что смог помочь:)
 Daniel Magliola21 сент. 2010 г., 15:04
Куамис, большое спасибо за ваш ответ. Некоторые комментарии: я не эксперт по Linux, но, похоже, я использую 25% оперативной памяти, если правильно читаю вывод htop. Я знаю, что эта система кеширования плохая. Если бы это был ASP.Net вместо PHP, я бы запомнил эти данные в памяти. Но это ДЕЙСТВИТЕЛЬНО мало, чтобы начать использовать memcache или даже иметь более одного сервера. Я знаю, что это будет иметь проблему с масштабируемостью, если сайт будет продолжать расти, но сейчас переход на более «серьезную» систему кэширования не имеет особого смысла.

действительно быстрое решение, если вы хотите гарантировать постоянное низкое время открытия. Возможно, ваша ОС выполняет синхронизацию диска, фиксацию файлов базы данных или другие вещи, которые вы не можете обойти.

Я предлагаю использовать memcached, redis или даже mongoDB для таких задач. Вы даже можете написать свой собственный демон кэширования, даже в php (однако это совершенно не нужно и может быть сложно).

Если вы абсолютно уверены, что вы можете решить эту задачу только с помощью этого файлового кэша, и вы находитесь под Linux, попробуйте использовать другой планировщик дискового ввода-вывода, например, дедлайн, ИЛИ (cfq И уменьшите приоритет процесса PHP до -3 / -4).

 Daniel Magliola21 сент. 2010 г., 15:08
Если честно, я знаю, что есть лучшие способы сделать это. Я унаследовал большую кодовую базу, которая сделала это, и у меня не было большого бюджета (или не нужно), чтобы перестроить все это. Я знаю, что это дерьмовый подход, но он должен бытьдостаточно хорошо по крайней мере, надолго, учитывая наш уровень трафика. Поэтому я пытаюсь обойти это без переписывания большого количества кода. Если я не могу, то я пойду в более сложные решения.

Ваш ответ на вопрос