блокировка файлов в PHP (тип чтения / записи) - PullRequest
4 голосов
/ 21 сентября 2010

У меня есть сценарий, когда один процесс 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, ноwrite - это обычное PHP-выполнение «командной строки», выполняемое cron'ом из Linux, оно не проходит через Apache.

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

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

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

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

Ответы [ 2 ]

3 голосов
/ 21 сентября 2010

Я могу подумать о 3 возможных проблемах:

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

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

  • поместите этот файл на виртуальный диск http://www.cyberciti.biz/faq/howto-create-linux-ram-disk-filesystem/.Это должен быть самый простой способ избежать частого попадания на диск без других серьезных изменений.
  • использовать memcache.Он очень быстрый, когда используется локально, хорошо масштабируется, используется «большими» игроками.http://www.php.net/manual/en/book.memcache.php
  • использовать общую память.Он был разработан для того, что вы пытаетесь сделать здесь ... имея «зону общей памяти» ...
  • измените планировщик cron, чтобы он обновлялся меньше, возможно, внедрите какую-то систему событий, так что это будет толькообновляйте кеш при необходимости, а не по времени
  • сделайте так, чтобы «пишущий» скрипт записывал в 3 файла разные, и «читатели» читали из одного из файлов случайным образом.Это может позволить «распределение» блокировки по большему количеству файлов и может уменьшить вероятность того, что определенный файл заблокирован при записи в него ... но я сомневаюсь, что это принесет какие-либо заметные преимущества.
0 голосов
/ 21 сентября 2010

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

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

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

...