Al experimentar con el ZeroMQ
Push/Pull
(lo que ellos llaman Pipeline
) tipo socket, estoy teniendo dificultades para entender la utilidad de este patrón. Se factura como un "equilibrador de carga".ZeroMQ Patrón push/pull utilidad
Dado que un servidor único envía tareas a un número de trabajadores, Push/Pull repartirá las tareas entre todos los clientes. 3 clientes y 30 tareas, cada cliente obtiene 10 tareas: client1 obtiene tareas 1, 4, 7, ... client2, 2, 5, ... y así sucesivamente. Lo suficientemente justo. Literalmente.
Sin embargo, en la práctica, a menudo existe una mezcla no homogénea de complejidad de tareas o recursos de computación del cliente (o disponibilidad), entonces este patrón se rompe mal. Todas las tareas parecen estar programadas de antemano, y el servidor no tiene conocimiento del progreso de los clientes o si están disponibles. Si el cliente1 se cae, sus tareas restantes no se envían a los demás clientes, sino que permanecen en cola para el cliente1. Si el cliente1 permanece inactivo, entonces esas tareas nunca se manejan. Por el contrario, si un cliente es más rápido en el procesamiento de sus tareas, no obtiene más tareas y permanece inactivo, ya que siguen programadas para los otros clientes.
El uso de REQ/REP
es una posible solución; las tareas solo se dan a un recurso disponible.
Entonces, ¿me falta algo? ¿Cómo se usa Push/Pull
de manera efectiva? ¿Hay alguna manera de manejar la asimetría de clientes, tareas, etc. con este tipo de socket?
Gracias!
Aquí está un ejemplo simple de 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)
fuego hasta 3 clientes con un parámetro de retardo en la línea de comandos (es decir, 1, 1, y 0.1) y luego el servidor, y ver cómo todas las tareas se distribuyen de manera uniforme. Luego mata a uno de los clientes para ver que no se manejan las tareas restantes.
Descomente las líneas indicadas para cambiarlo a un socket de tipo Req/Rep
y vea un equilibrador de carga más efectivo.
Cuando un trabajador falla, ¿hay un mecanismo para detectar esto y recuperar las tareas en cola que se han asignado pero no se han enviado? Algo así como un tiempo de espera con una redistribución de tareas. – CNK
Si desea detectar trabajadores fallidos, debe agregarlo usted mismo. Es relativamente fácil: recopile todos los resultados y, si falta alguno, reinicie todo el lote. El fracaso es bastante raro que este simple enfoque brutal lo maneje bien. –
Bueno, todavía está en los documentos que se mantienen aquí: http://zguide.zeromq.org/page:all – easytiger