2012-09-20 52 views
34

Al experimentar con el ZeroMQPush/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.

Respuesta

47

No es un balanceador de carga, esta fue una explicación errónea que permaneció en los documentos de 0MQ por un tiempo. Para equilibrar la carga, debe obtener información de parte de los trabajadores sobre su disponibilidad. PUSH, como DEALER, es un distribuidor de turnos. Es útil por su velocidad bruta y su simplicidad. No necesita ningún tipo de charla, solo transfiera las tareas a la tubería y se pulverizan a todos los trabajadores disponibles tan rápido como la red pueda manejarlos.

El patrón es útil cuando se realizan muchas tareas pequeñas y donde los trabajadores entran y salen con poca frecuencia. El patrón no es bueno para las tareas más grandes que tardan en completarse porque entonces desea una sola cola que envíe nuevas tareas solo a los trabajadores disponibles. También sufre de un antipatrón en el que si un cliente envía muchas tareas y luego los trabajadores se conectan, el primer trabajador tomará aproximadamente 1,000 mensajes mientras los demás aún están ocupados conectando.

Puede hacer su propio enrutamiento de alto nivel de varias maneras. Mire los patrones de LRU en la Guía: en esto los trabajadores explícitamente le dicen al agente "listo". También puede hacer un control de flujo basado en crédito, y esto es lo que haría en cualquier situación de equilibrio de carga real. Es una generalización del patrón LRU.Ver http://hintjens.com/blog:15

+0

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

+6

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. –

+2

Bueno, todavía está en los documentos que se mantienen aquí: http://zguide.zeromq.org/page:all – easytiger