En expérimentant avec le ZeroMQ
Push/Pull
(ce qu'ils appellent Pipeline
) type de socket, j'ai du mal à comprendre l'utilité de ce modèle. Il est présenté comme un "équilibreur de charge".
Étant donné qu'un seul serveur envoie des tâches à un certain nombre de travailleurs, Push/Pull distribuera également les tâches entre tous les clients. 3 clients et 30 tâches, chaque client reçoit 10 tâches: client1 obtient les tâches 1, 4, 7, ... client2, 2, 5, ... et ainsi de suite. C'est suffisant. Au sens propre.
Cependant, dans la pratique, il y a souvent un mélange non homogène de complexité des tâches ou de ressources de calcul client (ou disponibilité), alors ce modèle casse mal. Toutes les tâches semblent être planifiées à l'avance, et le serveur n'a aucune connaissance de la progression des clients ou s'ils sont même disponibles. Si client1 tombe en panne, ses tâches restantes ne sont pas envoyées aux autres clients, mais restent en file d'attente pour client1. Si client1 reste arrêté, ces tâches ne sont jamais gérées. Inversement, si un client est plus rapide dans le traitement de ses tâches, il n'obtient pas d'autres tâches et reste inactif, car elles restent planifiées pour les autres clients.
En utilisant REQ/REP
est une solution possible; les tâches ne sont alors données qu'à une ressource disponible.
Alors est-ce que je manque quelque chose? Comment est Push/Pull
pour être utilisé efficacement? Existe-t-il un moyen de gérer l'asymétrie des clients, des tâches, etc., avec ce type de socket?
Merci!
Voici un simple 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)
Lancez 3 clients avec un paramètre de délai sur la ligne de commande (c.-à-d. 1, 1 et 0,1), puis le serveur, et voyez comment toutes les tâches sont réparties uniformément. Ensuite, tuez l'un des clients pour voir que ses tâches restantes ne sont pas gérées.
Décommentez les lignes indiquées pour passer à un Req/Rep
tapez socket et regardez un équilibreur de charge plus efficace.
Ce n'est pas un équilibreur de charge, c'était une explication défectueuse qui est restée dans les documents 0MQ pendant un certain temps. Pour effectuer l'équilibrage de charge, vous devez obtenir des informations des travailleurs sur leur disponibilité. Push, comme DEALER, est un distributeur à tour de rôle. Il est utile pour sa vitesse brute et sa simplicité. Vous n'avez besoin d'aucune sorte de bavardage, pompez simplement les tâches dans le pipeline et elles sont diffusées à tous les employés disponibles aussi rapidement que le réseau peut les gérer.
Le modèle est utile lorsque vous effectuez un nombre très élevé de petites tâches et lorsque les travailleurs vont et viennent rarement. Le modèle n'est pas adapté aux tâches plus volumineuses qui prennent du temps, car vous souhaitez alors une file d'attente unique qui n'envoie de nouvelles tâches qu'aux travailleurs disponibles. Il souffre également d'un anti-modèle où si un client envoie de nombreuses tâches et que les travailleurs se connectent, le premier travailleur saisira 1 000 messages environ tandis que les autres sont toujours occupés à se connecter.
Vous pouvez créer votre propre routage de niveau supérieur de plusieurs manières. Regardez les modèles LRU dans le Guide: dans ce document, les travailleurs disent explicitement au courtier "prêt". Vous pouvez également faire un contrôle de flux basé sur le crédit, et c'est ce que je ferais dans n'importe quelle situation réelle d'équilibrage de charge. C'est une généralisation du modèle LRU. Voir http://hintjens.com/blog:15