Это правильный способ использования очереди сообщений?
Я новичок в очередях обмена сообщениями, и сейчас я использую ZeroMQ
на моем Linux-сервере. Я использую PHP
для записи как клиента, так и сервера. Это в основном используется для обработки push-уведомлений.
Я использую базовый REQ
- REP
Формально-коммуникационный шаблон для отдельных экземпляров ZMQContext
с интерфейсом ввода/вывода, как они продемонстрировали.
Вот минимальный zeromqServer.php
код:
include("someFile.php");
$context = new ZMQContext(1);
// Socket to talk to clients
$responder = new ZMQSocket($context, ZMQ::SOCKET_REP);
$responder->bind("tcp://*:5555");
while (true) {
$request = $responder->recv();
printf ("Received request: [%s]\n", $request);
// -----------------------------------------------------------------
// Process push notifications here
//
sleep (1);
// -----------------------------------------------------------------
// Send reply back to client
$responder->send("Basic Reply");
}
И вот минимизированный ZeroMQ
клиент:
$context = new ZMQContext();
// Socket to talk to server
echo "Connecting to hello world server…\n";
$requester = new ZMQSocket($context, ZMQ::SOCKET_REQ);
$check = $requester->connect("tcp://localhost:5555");
var_dump($check);
$requester->send("json string payload with data required to process push notifications.");
//$reply = $requester->recv();
Итак, что я делаю? Я запускаю zeromqServer.php
в качестве фоновой службы, используя команду linux
nohup php zeromqServer.php &
Это выполняется как фоновый процесс. Теперь, когда клиент называет его, он выполняет требуемую работу.
Но проблема в том, что мне нужно перезапустить процесс каждый раз, когда есть изменения в любом из файлов (включая те include
-ed в файле zeromqServer
).
И более того, как-то через 2-3 дня он просто перестает работать. Процесс не останавливается, но он просто перестает работать.
Мне кажется, что это должна быть проблема сокета, возможно, сокет больше не открыт. В это время мне нужно перезапустить процесс zeromqServer.php
.
Q1:
В чем может быть проблема?
Q2:
И каков правильный способ сделать это?
Ответы
Ответ 1
Это неправильный способ использования очереди сообщений.
A1: Проблема заключается в том, что ваш сервер, наконец, должен заблокировать, так как клиентский код не получает ответа, а для этого требуется REQ/REP
-pattern. zeromqServer.php
на стороне REP
просто не будет пытаться recv()
получить другое сообщение от связанного клиента (на стороне REQ
модуля формальной связи), пока клиент не будет физически доставлен (во внутренний буфер) и имеет recv()
- значение "ответа" со стороны zeromqServer.php
.
Более ранние версии ZeroMQ, вер. 2.1 и др., Использовались для неограниченного, бесконечного размера ограничения по умолчанию для внутренних очередей сообщений node и управления памятью, используемых для буферизации низкоуровневых потоков ввода-вывода, до того, как данные были скопированы в O/S -kernel и освобождены от занимаемой памяти ZeroMQ.
Новые версии ZeroMQ, ver 3.x +, имеют так называемые HWM -s (aka High-Water-Mark-s) по умолчанию "всего лишь 1000 сообщений, выделяющих" короткие ", после чего соответствующая часть такого ресурса ZeroMQ начинает блокировать или отбрасывать сообщения.
В то время как реактивная попытка явно увеличить управление HWM-настройками выглядит грязным способом решения основной ошибки дизайна, другое предупреждение ZeroMQ справедливо для этого, чтобы еще раз предостеречь пойти именно в этом направлении (ØMQ не гарантирует, что сокет будет принимать сообщения ZMQ_SNDHWM
, а фактический предел может быть целых 60-70% ниже в зависимости от потока сообщений в сокете).
Забыть или не сделать этого ( Ссылка:, поскольку код OP уже продемонстрировал):
//$reply = $requester->recv();
означает, что ваш REQ/REP
Формальный шаблон связи "маятник" становится необратимо запертым (навсегда).
A2: Основной REQ/REP
Формальный коммуникационный паттерн звучит прямо, но имеет несколько опасных функций, наблюдаемая блокировка - всего лишь одно из них. Некоторые дополнительные шаги могут быть предприняты по коду, для развертывания XREQ/XREP
, DEALER/ROUTER
и других инструментов, но дизайн следует переупаковать, а не только SLOC
на SLOC
, поскольку, похоже, много что нужно реализовать, прежде чем разрабатывать код. Одна из главных ошибок заключается в том, что сообщение отправляется после того, как был заказан метод send()
. Не в ZeroMQ.
Также код-код должен воспринимать неопределенный характер сообщения, доставляющего и обрабатывающего должным образом как недостающую проблему сообщения, так и любой инцидент блокировки с распределенным сервисом (тупиковая ситуация, ожидание, переполнение буфера-порога, старый/новый-API конфликты, так как нет никакой явной гарантии ни один из ваших одноранговых узлов обмена сообщениями (в ZeroMQ отсутствует центральный брокер сообщений) имеет ту же самую версию API/протокола ZeroMQ, реализованную на нем, на стороне localhost, поэтому действительно есть много новых точек во время разработки кода)
Лучший способ сделать это
Если вы можете доверять и верить в практический опыт, лучшим вашим следующим шагом должно быть скачать и прочитать сказочный Pieter HINTJENS ' книга "Код подключен, том 1" , где у Pieter есть много информации о распределенной обработке, включая множество подсказок и направлений для надежных шаблонов, которые вы хотите реализовать.
Прочитайте книгу, это тоже стоит вашего времени, и вы, вероятно, будете многократно пересматривать книгу, если вы останетесь в распределенном программном обеспечении, поэтому не стесняйтесь начинать прямо сейчас, перепрыгивая на такую кулинарную книгу на 400+ страниц из Мастер Мастеров, Питер ХИНЦЕНС из вопросов.
Почему? Реальный мир обычно намного сложнее
Только одно изображение, рис. 60 из вышеупомянутой книги, чтобы забыть о повторном использовании индивидуального архетипа и осознать необходимость надлежащей сквозной перспективы проектирования распределенной системы, включая предотвращение блокировки и стратегии взаимоблокировки:
![Transport Plane + SIG Plane]()
Чтобы иметь какую-то идею, загляните в следующий пример кода из простого распределенного обмена сообщениями, где aMiniRESPONDER
обрабатывает несколько каналов ZeroMQ.
![введите описание изображения здесь]()
Как улучшить вашу реализацию в довольно большом веб-домене PHP-приложения?
Узнайте, как предотвратить конфликты (дизайн-мудрый) и дескриптор (deux-ex-machina) другие конфликты.
У PHP есть собственные правильные синтаксические конструкторы для этого типа алгоритмизации, но архитектура и дизайн в ваших руках, от начала до конца.
Чтобы понять, насколько большен стиль { try:, except:, finally: }
, ориентированный на столкновение, с установкой/инфраструктурой системы ZeroMQ/компонентом системы /ZeroMQ, проверьте номера [SoW]
только по номерам строк:
14544 - 14800 // a safe infrastructure setup on aMiniRESPONDER side ~ 256 SLOCs
15294 - 15405 // a safe infrastructure graceful termination ~ 110 SLOCs
по сравнению с основной логикой сегмента обработки событий aMiniRESPONDER
example
14802 - 15293 // aMiniRESPONDER logic, incl. EXC-HANDLERs ~ 491 SLOCs
Окончательная заметка о распределенных системах на основе ZeroMQ
Требуя? Да, но очень мощный, масштабируемый, быстрый и действительно полезный при правильном использовании. Не стесняйтесь вкладывать свое время и усилия, чтобы приобрести и управлять своими знаниями в этой области. Все ваши дальнейшие проекты в области программного обеспечения могут просто извлечь выгоду из этих профессиональных инвестиций.
Ответ 2
Я могу лишь частично ответить на этот вопрос. Я понятия не имею, почему процесс зависает через 2-3 дня.
В общей сложности PHP script загружается один раз в script время выполнения, похоже, что это ограничение не существует. Однако ваш текущий код можно переписать следующим образом:
somefile.php
$context = new ZMQContext(1);
// Socket to talk to clients
$responder = new ZMQSocket($context, ZMQ::SOCKET_REP);
$responder->bind("tcp://*:5555");
while (true) {
$request = $responder->recv();
printf ("Received request: [%s]\n", $request);
$subscriptParams = [
"Request" => $request //Add more parameters here as needed
];
$result = shell_exec("php work.php ".base64_encode(serialize($subscriptParams)));
// Send reply back to client
$responder->send("Basic Reply");
}
work.php
if (!isset($argv[0])) {
die("Need an argument");
}
$params = unserialize(base64_decode($argv[0]));
//Validate parameters
$request = $params["Request"];
// Do some 'work'
//Process push notifications here!
sleep (1);
Здесь мои предположения:
-
Часть настройки script, например. установка $context
и $responder
будет оставаться постоянной навсегда (или вы могли бы жить со временем простоя, необходимым для перезапуска script из-за изменений в этом).
-
Начало и конец цикла остаются постоянными, я полагаю, что shell_exec
вернет ответ, который может быть использован ответчиком в качестве фактического ответа.
Дополнительные пояснения:
Я использую serialize
для передачи массива аргументов, которые нужно использовать work.php
. Я делаю декодирование base64
, потому что я хочу, чтобы весь аргумент поместился в $argv[0]
и не получил разделение на потенциальные пространства, найденные в аргументах.
То же сочетание serialize -> base64_encode
и base64_decode -> deserialize
может использоваться для результата work.php
.
Обратите внимание, что я лично не пробовал этот код, поэтому я не могу гарантировать, что он работает. Я просто не вижу причин, по которым он не должен работать (убедитесь, что php
находится в вашем пути или вызовите /usr/bin/php
в shell_exec
, если это не так).
Стоит отметить, что это решение будет довольно медленным, чем наличие всего кода в одном файле, но это стоимость обновления script на каждой итерации.
Ответ 3
Q2: И каков правильный способ сделать это?
Правильный способ сделать все, на мой взгляд, - выбрать лучший вариант, доступный для вас в начале, чтобы не вкладывать время в метод, который даст вам результаты второго сорта. У меня нет ничего против ZeroMQ
, хотя я следую логике, что программисты должны всегда стремиться делать самый чистый код и использовать самые лучшие инструменты. В случае создания очереди сообщений с PHP у вас будет намного больше успеха с Pheanstalk
: https://github.com/pda/pheanstalk
Это рекомендуемый вариант с открытым исходным кодом онлайн и отлично работает на Linux. Установка очереди очень проста, и я написал полный ответ о том, как установить pheanstalk в следующем разделе: Невозможно заставить Beanstalkd Queue работать для PHP
Pheanstalk использует библиотеку beanstalkd, которая очень легкая и эффективная. Чтобы создать очередь сообщений в качестве предложения, вы можете сделать это с помощью двух простых скриптов php:
Производитель сообщений:
<?php
$pheanstalk = new Pheanstalk('127.0.0.1:11300');
$pheanstalk
->useTube("my_queue")
->put("Hello World");
?>
Рабочий script:
<?php
if ($job = $pheanstalk
->watch('testtube')
->ignore('default')
->reserve())//retreives the job if there is one in the queue
{
echo $job->getData();//echos the message
$pheanstalk->delete($job);//deletes the job from the queue
}
}
?>
Производитель сообщений будет включен в страницу, где пользователь будет создавать сообщение, и это будет отправлено в очередь, сгенерированную beanstalkd. Рабочий script может быть спроектирован по-разному. Вы можете поместить его в цикл while для поиска новой очереди каждую секунду, и вы даже можете иметь несколько рабочих, которые ищут очередь. Pheanstalk очень эффективен и настоятельно рекомендуется.