2012-09-20 12 views
34

Nella sperimentazione del tipo di socket ZeroMQPush/Pull (quello che chiamano Pipeline), ho difficoltà a comprendere l'utilità di questo modello. È indicato come "bilanciamento del carico".Utilità del modello push/pull ZeroMQ

Dato un singolo server che invia le attività a un numero di dipendenti, Push/Pull distribuirà uniformemente le attività tra tutti i client. 3 client e 30 attività, ogni client riceve 10 attività: client1 ottiene attività 1, 4, 7, ... client2, 2, 5, ... e così via. Giusto. Letteralmente.

Tuttavia, nella pratica spesso c'è un mix non omogeneo di complessità delle attività o risorse di calcolo del client (o disponibilità), quindi questo schema si interrompe. Tutte le attività sembrano essere pianificate in anticipo e il server non è a conoscenza dell'avanzamento dei client o se sono disponibili. Se client1 si arresta, le attività rimanenti non vengono inviate agli altri client, ma rimangono accodate per client1. Se client1 rimane inattivo, queste attività non vengono mai gestite. Viceversa, se un client è più veloce nell'elaborare le sue attività, non ottiene ulteriori compiti e rimane inattivo, in quanto rimangono programmati per gli altri client.

L'utilizzo di REQ/REP è una possibile soluzione; le attività vengono quindi assegnate solo a una risorsa disponibile.

Quindi mi manca qualcosa? In che modo è possibile utilizzare efficacemente Push/Pull? C'è un modo per gestire l'asimmetria di client, attività, ecc. Con questo tipo di socket?

Grazie!

Ecco un semplice esempio di 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) 

fuoco fino a 3 clienti con un parametro di ritardo sulla riga di comando (ad esempio, 1, 1, e 0,1) e quindi il server, e vedere come tutti i compiti sono equamente distribuiti. Quindi uccidere uno dei client per verificare che le attività rimanenti non vengano gestite.

Decommentare le linee indicate per passare a un socket di tipo Req/Rep e guardare un bilanciamento del carico più efficace.

risposta

47

Non è un bilanciamento del carico, questa è stata una spiegazione errata che è rimasta nei documenti 0MQ per un po '. Per eseguire il bilanciamento del carico, è necessario recuperare alcune informazioni dai lavoratori sulla loro disponibilità. PUSH, come DEALER, è un distributore round robin. È utile per la sua velocità grezza e semplicità. Non è necessario alcun tipo di chatter, basta pompare i compiti lungo la pipeline e vengono distribuiti a tutti i lavoratori disponibili con la stessa rapidità con cui la rete li gestisce.

Il modello è utile quando si eseguono numeri molto elevati di piccoli compiti e dove i lavoratori vanno e vengono di rado. Il pattern non è adatto a compiti più grandi che richiedono tempo per essere completati, in quanto si desidera una singola coda che manda nuove attività solo ai lavoratori disponibili. Soffre anche di un anti-pattern in cui se un client invia molte attività e quindi i lavoratori si connettono, il primo operatore prenderà circa 1.000 messaggi mentre gli altri sono ancora impegnati a connettersi.

È possibile creare il proprio instradamento di livello superiore in diversi modi. Guarda i modelli di LRU nella Guida: in questo i lavoratori dicono esplicitamente al broker 'pronto'. Puoi anche fare il controllo del flusso basato sul credito, e questo è quello che farei in qualsiasi situazione di bilanciamento del carico reale. È una generalizzazione del modello LRU.Vedere http://hintjens.com/blog:15

+0

Quando un operatore non funziona, esiste un meccanismo per rilevare entrambi e recuperare le attività in coda di quelle che sono state assegnate ma non inviate? Qualcosa come un timeout con una ridistribuzione delle attività. – CNK

+6

Se si desidera rilevare lavoratori non funzionanti, è necessario aggiungerli personalmente. È relativamente facile: raccogliere tutti i risultati e se ne manca uno, riavviare l'intero batch. Il fallimento è abbastanza raro che questo semplice approccio brutale lo gestisca bene. –

+2

Bene è ancora nei documenti mantenuti qui: http://zguide.zeromq.org/page:all – easytiger