47 votes

Utilité du modèle Push/Pull de ZeroMQ

En expérimentant le ZeroMQ Push/Pull (ce qu'ils appellent Pipeline ), j'ai du mal à comprendre l'utilité de ce modèle. Il est présenté comme un "équilibreur de charge".

Dans le cas d'un serveur unique envoyant des tâches à un certain nombre de travailleurs, Push/Pull répartira les tâches de manière égale entre tous les clients. 3 clients et 30 tâches, chaque client reçoit 10 tâches : client1 reçoit les tâches 1, 4, 7,... client2, 2, 5,... et ainsi de suite. C'est équitable. Littéralement.

Cependant, dans la pratique, il y a souvent un mélange non homogène de la complexité des tâches ou des ressources informatiques du client (ou de leur disponibilité), alors ce modèle se casse la figure. Toutes les tâches semblent être programmées à l'avance, et le serveur n'a aucune connaissance de la progression des clients ou même de leur disponibilité. Si le client 1 tombe en panne, ses tâches restantes ne sont pas envoyées aux autres clients, mais restent en file d'attente pour le client 1. Si le client1 reste en panne, ces tâches ne sont jamais traitées. Inversement, si un client est plus rapide dans le traitement de ses tâches, il ne reçoit pas d'autres tâches et reste inactif, car elles restent programmées pour les autres clients.

Utilisation de REQ/REP est une solution possible ; les tâches ne sont alors confiées qu'à une ressource disponible .

Alors j'ai raté quelque chose ? Comment est-ce que 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 exemple simple en 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 (par exemple, 1, 1, et 0.1) et ensuite le serveur, et voyez comment toutes les tâches sont distribuées de manière égale. Ensuite, tuez l'un des clients pour voir si ses tâches restantes ne sont pas traitées.

Décommentez les lignes indiquées pour le changer en un Req/Rep et regarder un équilibreur de charge plus efficace.

66voto

Pieter Hintjens Points 3677

Ce n'est pas un équilibreur de charge, c'est une explication erronée qui est restée dans la documentation de 0MQ pendant un certain temps. Pour faire de l'équilibrage de charge, vous devez obtenir des informations en retour des travailleurs sur leur disponibilité. PUSH, comme DEALER, est un distributeur round-robin. Il est utile pour sa vitesse brute et sa simplicité. Vous n'avez besoin d'aucune sorte de bavardage, il suffit de pomper les tâches dans le pipeline et elles sont distribuées à tous les travailleurs disponibles aussi rapidement que le réseau peut les gérer.

Ce modèle est utile lorsque vous effectuez un nombre très élevé de petites tâches, et lorsque les travailleurs vont et viennent peu fréquemment. Le modèle n'est pas bon pour les tâches plus importantes qui prennent du temps à accomplir, car il faut alors une file d'attente unique qui envoie les nouvelles tâches uniquement aux travailleurs disponibles. Il souffre également d'un anti-modèle : si un client envoie de nombreuses tâches et que des travailleurs se connectent, le premier travailleur recevra environ 1 000 messages pendant que les autres seront occupés à se connecter.

Vous pouvez créer votre propre gamme de niveau supérieur de plusieurs façons. Regardez les modèles LRU dans le Guide : dans ce cas, les travailleurs disent explicitement au courtier qu'ils sont "prêts". Vous pouvez aussi faire du contrôle de flux basé sur le crédit, et c'est ce que je ferais dans toute situation réelle d'équilibrage de charge. C'est une généralisation du modèle LRU. Voir http://unprotocols.org/blog:15

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X