Nella sperimentazione del tipo di socket ZeroMQ
Push/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.
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
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. –
Bene è ancora nei documenti mantenuti qui: http://zguide.zeromq.org/page:all – easytiger