Масштабируемая, отложенная обработка PHP - PullRequest
19 голосов
/ 25 июня 2010

Я работаю над онлайн-приложением PHP, для которого требуется отложенное событие PHP.По сути, мне нужно иметь возможность выполнять произвольный код PHP через много секунд (но это могут быть дни) после первоначального обращения к URL.Мне нужно довольно точное выполнение этих событий PHP, а также я хочу, чтобы оно было достаточно масштабируемым.Я пытаюсь избежать необходимости планировать работу cron каждую секунду.Я изучал Gearman , но, похоже, он не дает возможности планировать события, и, как я понимаю, PHP не предназначен для работы в качестве демона.

Было бы идеально, если бы я мог указать какому-либо внешнему процессу опросить URL-адрес «средства проверки событий» на PHP-сервере в то время, когда должно быть запущено следующее событие.Это время опроса нужно будет уменьшить или увеличить по желанию, так как событие может быть удалено и добавлено в очередь и.Есть какие-нибудь идеи по поводу элегантного способа сделать это? Существует просто много дополнительных затрат на вызов PHP извне (необходимость разбора HTTP-запроса или вызов через CLI), чтобы сделать эту идею осуществимой для моих нужд.

Мой текущий план - написать PHP-демон, который будет запускать событие и взаимодействовать с ним с PHP-сервера с gearman.Демон PHP будет построен на SplMinHeap , так что, надеюсь, производительность не будет плохой.Эта идея оставляет неприятный привкус во рту, и мне было интересно, есть ли у кого идея получше? Идеи немного изменились.Читать Редактировать 2.

РЕДАКТИРОВАТЬ:

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

РЕДАКТИРОВАТЬ 2:

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

Лично я считаю, что единственное чистое решение, которое соответствует требованиям для этого проектанаписать PHP-демон, который обрабатывает отложенные события.Я начал писать то, что я думаю о first PHP runloop.Он управляет просмотром сокетов и выполнением отложенных событий PHP.Надеюсь, когда я закончу с этим проектом, я смогу опубликовать источник, если кто-то из вас заинтересован в этом.До сих пор в тестировании это было многообещающим решением (никаких проблем с утечкой памяти или нестабильностью).

РЕДАКТИРОВАТЬ 3: Вот ссылка на библиотеку цикла событий PHP под названием LooPHP для тех, ктокому интересно.

TL; Требования DR

  • Вызов (желательно изначально) PHP с задержкой (от секунд до дней)
  • Произвольно обрабатывать создание / обновление / удаление событий (я ожидаю большое количество отмененных вызовов).
  • Обработка высокой загрузки запланированных событий (100-1000 в секунду на сервер)
  • Звонки должны быть в пределах одной секунды от запланированного времени
  • На данный момент я не готов переписать кодовую базу на другой язык (возможно, когда-нибудь я буду)

Ответы [ 15 ]

0 голосов
/ 25 июня 2010

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

Вы даже можете масштабировать его, разветвив или запустив другой php-файл, чтобы фактически запустить событие. Тогда вы можете запустить более одного события одновременно.

0 голосов
/ 25 июня 2010

Не могу придумать ничего, что делает все, что вы просили:

  • должно быть очень точным
  • задержка на длительные периоды времени
  • способностьудалить / изменить время события

Тривиальным способом было бы использовать комбинацию следующих функций:

set_time_limit(0);
ignore_user_abort(true);
time_sleep_until(strtotime('next Friday'));
// execute code

Однако, как @deceze сказал, что, вероятно, неочень хорошая идея, поскольку, если вы установите высокую задержку, Apache может в конечном итоге убить дочерний процесс (если вы не используете PHP CLI, это упростит задачу).Это также не позволяет вам изменять / удалять событие, если вы не настроили более сложную логику и базу данных для хранения событий.Кроме того, register_shutdown_function() может быть полезно, если вы хотите пойти по этому пути.

На мой взгляд, лучшим подходом было бы создание задания CRON.

0 голосов
/ 25 июня 2010

Я не уверен, почему вы пытаетесь избежать cron. Вы можете создать очередь запросов в таблице, и cron запустит процесс проверки текущих заданий.

Есть несколько вопросов, в зависимости от ваших точных требований. Например:

  • Насколько точным должен быть звонок?
  • Сколько времени займет каждый звонок?
  • Что такое нормальная и пиковая нагрузка в какой-либо данный период?

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

У меня есть много демонов, которые запускают PHP (используя daemontools). При таком подходе вы можете хранить запросы в ядре и выполнять любые временные параметры, которые вам нужны.

Однако, если вам нужно точное и достоверное время, вам, вероятно, следует вообще отказаться от PHP.

0 голосов
/ 25 июня 2010

Используйте функцию сна: http://php.net/sleep

0 голосов
/ 25 июня 2010

Что насчёт этого:

http://www.phpjobscheduler.co.uk/

...