Подтвердить что ты не робот

Полезность ZeroMQ Push/Pull

При экспериментировании с типом сокета ZeroMQ Push/Pull (что они называют Pipeline) мне трудно понять полезность этого шаблона. Он был объявлен как "балансировщик нагрузки".

Учитывая, что один сервер отправляет задачи нескольким работникам, Push/Pull будет равномерно распределять задачи между всеми клиентами. 3 клиента и 30 задач, каждый клиент получает 10 задач: client1 получает задания 1, 4, 7,... client2, 2, 5,... и так далее. Справедливо. Буквально.

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

Использование REQ/REP - одно из возможных решений; задачи затем предоставляются только доступному ресурсу.

Я что-то упускаю? Как эффективно использовать Push/Pull? Есть ли способ справиться с асимметрией клиентов, задач и т.д. С этим типом сокета?

Спасибо!

Вот простой пример Python:

# server

import zmq
import time

context = zmq.Context()
socket = context.socket(zmq.PUSH)
#socket = context.socket(zmq.REP)   # uncomment for Req/Rep

socket.bind("tcp://127.0.0.1:5555")

i = 0
time.sleep(1)   # naive wait for clients to arrive

while True:
  #msg = socket.recv()    # uncomment for Req/Rep
  socket.send(chr(i))
  i += 1 
  if i == 100:
    break

time.sleep(10)   # naive wait for tasks to drain

.

# client

import zmq
import time
import sys

context = zmq.Context()

socket = context.socket(zmq.PULL)
#socket = context.socket(zmq.REQ)    # uncomment for Req/Rep

socket.connect("tcp://127.0.0.1:5555")

delay = float(sys.argv[1])

while True:
  #socket.send('')     # uncomment for Req/Rep
  message = socket.recv()
  print "recv:", ord(message)
  time.sleep(delay)

Запустите 3 клиента с параметром задержки в командной строке (то есть 1, 1 и 0,1), а затем сервером и посмотрите, как распределяются все задачи. Затем убейте одного из клиентов, чтобы убедиться, что его оставшиеся задачи не обрабатываются.

Раскомментируйте строки, указанные для переключения на гнездо типа REQ/REP и посмотрите более эффективный балансировщик нагрузки.

4b9b3361

Ответ 1

Это не балансировка нагрузки, это было ошибочное объяснение, которое некоторое время оставалось в документах 0MQ. Чтобы выполнить балансировку нагрузки, вы должны получить от работников информацию об их доступности. PUSH, как DEALER, является дистрибьютором с круговым движением. Это полезно для его сырой скорости и простоты. Вам не нужна какая-либо болтовня, просто насосные работы по трубопроводу, и они разбрызгиваются всем доступным рабочим так же быстро, как сеть может их обрабатывать.

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

Вы можете сделать свою собственную маршрутизацию более высокого уровня несколькими способами. Посмотрите на шаблоны LRU в Руководстве: в этом рабочие явно указывают брокеру "готов". Вы также можете использовать управление потоком на основе кредитов, и это то, что я сделал бы в любой реальной ситуации балансировки нагрузки. Это обобщение шаблона LRU. См. http://hintjens.com/blog:15