При экспериментировании с типом сокета 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
и посмотрите более эффективный балансировщик нагрузки.