асинхронная обработка с помощью PHP - один работник на задание


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

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

Как лучше всего реализовать такую систему, как эта? Я вижу:

  1. Разветвление работника от менеджера - это, по-видимому, вариант самого низкого уровня, и мне пришлось бы самому внедрить систему мониторинга. Apache является веб-сервером, поэтому, похоже, для этой опции потребуется, чтобы все PHP-работники запускались через FastCGI.
  2. Используйте какую-то очередь заданий/сообщений. (gearman, beanstalkd, RabbitMQ и т.д.) - Изначально это казалось очевидным выбором. После некоторых исследований я несколько запутался во всех вариантах. Например, Gearman выглядит так, как будто он предназначен для огромных распределенных систем, в которых имеется фиксированный пул workers...so Я не знаю, подходит ли это для того, что мне нужно (один работник на работу).
Author: Josh Johnson, 2010-08-18

3 answers

Ну, если вы работаете в Linux, вы можете использовать pcntl_fork чтобы раскошелиться на детей. Затем "мастер" наблюдает за детьми. Каждый ребенок выполняет свою задачу и затем существует нормально.

Лично мне в моих реализациях никогда не требовалась очередь сообщений. Я просто использовал массив в "мастере" с замками. Когда ребенок устраивался на работу, он записывал файл блокировки с идентификационным номером работы. Затем мастер подождет, пока этот ребенок не выйдет. Если файл блокировки все еще существует после дочернего вышел, затем я знаю, что задача не была выполнена, и повторно запустите дочернее устройство с тем же заданием (после удаления файла блокировки). В зависимости от вашей ситуации вы можете реализовать очередь в простой таблице базы данных. Вставьте задания в таблицу и проверяйте таблицу в мастере каждые 30 или 60 секунд на наличие новых заданий. Затем удалите их из таблицы только после того, как ребенок закончит (и ребенок удалит файл блокировки). Это вызвало бы проблемы, если бы у вас одновременно работало более одного "мастера", но вы можно было бы реализовать глобальный "главный pid-файл" для обнаружения и предотвращения нескольких экземпляров...

И я бы не советовал разветвляться с помощью FastCGI. Это может привести к некоторым очень неясным проблемам, поскольку окружающая среда должна сохраняться. Вместо этого используйте CGI, если у вас должен быть веб-интерфейс, но в идеале используйте приложение CLI (deamon). Для взаимодействия с мастером из других процессов вы можете либо использовать сокеты для связи по протоколу TCP, либо создать файл FIFO для связи.

Что касается обнаруживая зависших работников, вы могли бы внедрить систему "сердцебиения", в которой ребенок каждые столько секунд выдает SIG_USR1 главному процессу. Затем, если вы не слышали о ребенке в течение двух или трех раз за это время, его могут повесить. Но дело в том, что, поскольку PHP не является многопоточным, вы не можете сказать, завис ли ребенок или он просто ожидает блокирующего ресурса (например, вызова базы данных)... Что касается реализации "сердцебиения", вы можете использовать функцию tick для автоматизации сердцебиения (но имейте в виду, что блокирование вызовов все равно не будет выполняться)...

 8
Author: ircmaxell, 2010-08-18 14:36:04
 1
Author: JMW, 2014-05-06 16:18:06

В то время как вы выполняете асинхронную одну задачу со многими заданиями с помощью pcntl_fork или будете создавать запрос на сохраняемость каждые (ы) секунды, будьте осторожны с высоким потреблением ЦП, вы можете получить зависшую память для обработки, потому что снова не может быть выделена память, я думаю, что лучший выбор, который вы можете полностью построить с помощью Gearman, или вы можете попробовать с облачным работником, таким как IronWorker.

 1
Author: Faizal Pribadi, 2016-03-31 04:59:28