Как работнику ZeroMQ безопасно «повесить трубку»? - PullRequest
20 голосов
/ 12 сентября 2010

Я начал использовать ZeroMQ на этой неделе, и при использовании шаблона «запрос-ответ» я не уверен, как заставить работника безопасно «повесить» и закрыть свой сокет, возможно, не отбрасывая сообщение и не вызывая клиента, который отправил это сообщение никогда не получить ответ. Представьте себе работника, написанного на Python, который выглядит примерно так:

import zmq
c = zmq.Context()
s = c.socket(zmq.REP)
s.connect('tcp://127.0.0.1:9999')
while i in range(8):
    s.recv()
    s.send('reply')
s.close()

Я проводил эксперименты и обнаружил, что клиент с 127.0.0.1:9999 типа сокета zmq.REQ, который делает запрос с честной очередью, просто может потерпеть неудачу, если алгоритм честной очереди выберет вышеуказанного работника сразу после работник выполнил последний send(), но перед тем, как запустить следующий close() метод. В этом случае кажется, что запрос получен и буферизован стеком ØMQ в рабочем процессе и что запрос теряется, когда close() выбрасывает все, что связано с сокетом.

Как рабочий может отсоединить «безопасно» - есть ли какой-либо способ подать сигнал «Я больше не хочу сообщений», затем (а) перебрать все окончательные сообщения, которые поступили во время передачи сигнала, (б) сгенерировать их ответы, а затем (с) выполнить close() с гарантией того, что никакие сообщения не будут выброшены?

Редактировать: Я полагаю, что необработанное состояние, в которое я хотел бы войти, является "полузакрытым" состоянием, когда дальнейшие запросы не могут быть получены - и отправитель узнает об этом - но где возврат путь по-прежнему открыт, так что я могу проверить свой входящий буфер на одно последнее поступившее сообщение и ответить на него, если в буфере присутствует одно из них.

Редактировать: В ответ на хороший вопрос исправил описание, сделав количество ожидающих сообщений множественным, так как может быть много соединений, ожидающих ответов.

Ответы [ 6 ]

11 голосов
/ 07 декабря 2010

Вы, кажется, думаете, что пытаетесь избежать «простого» условия гонки, такого как в

... = zmq_recv(fd);
do_something();
zmq_send(fd, answer);
/* Let's hope a new request does not arrive just now, please close it quickly! */
zmq_close(fd);

, но я думаю, что проблема в том, что справедливая организация очередей (круговой прием) делает вещи еще более трудными: у вас уже может быть несколько запросов в очереди на вашего работника.Отправитель не будет ждать освобождения вашего работника, прежде чем отправлять новый запрос, если его очередь получать, поэтому во время вызова zmq_send другие запросы могут уже ждать.

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

Конечно, это означает использование XREP / XREQ, но я думаю, что оно того стоит.

Редактировать: Я написал некоторый код реализует другое направление , чтобы объяснить, что я имею в виду.

3 голосов
/ 30 июля 2011

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

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

Вы должны помнить, что в ZeroMQ имеется 0 очередей сообщений.Вовсе нет!Просто сообщения, буферизованные в отправителе или получателе, в зависимости от таких настроек, как High Water Mark и типа сокета.Если вам действительно нужны очереди сообщений, вам нужно написать приложение-брокер, чтобы справиться с этим, или просто переключиться на AMQP, где все взаимодействие осуществляется через стороннего брокера.

2 голосов
/ 28 октября 2010

Я тоже об этом думал.Возможно, вы захотите реализовать сообщение ЗАКРЫТЬ, которое уведомляет клиента о том, что работник уходит.Затем вы могли бы уволить работника в течение некоторого времени, прежде чем выключить.Конечно, не идеально, но возможно.

0 голосов
/ 23 января 2012

Существует конфликт интересов между посылкой запросов как можно быстрее работникам и получением надежности в случае сбоя или смерти работающего.Существует целый раздел Руководства ZeroMQ, в котором объясняются разные ответы на этот вопрос о надежности.Прочитайте это, это очень поможет.

tl; д-р работники могут / будут аварийно завершать работу, а клиентам нужна функция повторной отправки.В Руководстве для этого предусмотрен многократно используемый код на многих языках.

0 голосов
/ 22 ноября 2010

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

0 голосов
/ 01 октября 2010

Попробуйте спать перед звонком, чтобы закрыть.Это исправлено в 2.1, но пока не в 2.0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...