J'essaie de faire communiquer un programme python avec un autre programme python via zeromq en utilisant le modèle demande-réponse. Le programme client doit envoyer une demande au programme serveur qui répond.
J'ai deux serveurs tels que lorsqu'un serveur tombe en panne, l'autre prend le relais. La communication fonctionne parfaitement lorsque le premier serveur fonctionne, cependant, lorsque le premier serveur tombe en panne et lorsque je fais une demande au second serveur, je vois l'erreur:
zmp.error.ZMQError: l'opération ne peut pas être accomplie dans l'état actuel
Code du serveur 1:
# Run the server
while True:
# Define the socket using the "Context"
sock = context.socket(zmq.REP)
sock.bind("tcp://127.0.0.1:5677")
data = sock.recv().decode("utf-8")
res = "Recvd"
sock.send(res.encode('utf-8'))
Code du serveur 2:
# Run the server
while True:
# Define the socket using the "Context"
sock = context.socket(zmq.REP)
sock.bind("tcp://127.0.0.1:5877")
data = sock.recv().decode("utf-8")
res = "Recvd"
sock.send(res.encode('utf-8'))
Code de client:
# ZeroMQ Context For distributed Message amogst processes
context = zmq.Context()
sock_1 = context.socket(zmq.REQ)
sock_2 = context.socket(zmq.REQ)
sock_1.connect("tcp://127.0.0.1:5677")
sock_2.connect("tcp://127.0.0.1:5877")
try:
sock_1.send(data.encode('utf-8'), zmq.NOBLOCK)
socks_1.setsockopt(zmq.RCVTIMEO, 1000)
socks_1.setsockopt(zmq.LINGER, 0)
data = socks_1.recv().decode('utf-8') #receive data from the main node
except:
try:
#when server one fails
sock_2.send(data.encode('utf-8'), zmq.NOBLOCK)
socks_2.setsockopt(zmq.RCVTIMEO, 1000)
socks_2.setsockopt(zmq.LINGER, 0)
data = socks_2.recv().decode('utf-8')
except Exception as e:
print(str(e))
Quel est le problème avec cette approche? Comment puis-je résoudre ce problème?
REQ/REP
!Bien que le ZeroMQ soit un cadre puissant, il est nécessaire de comprendre sa composition interne pour la robuste et fiable conception et prototypage de systèmes distribués.
Après un examen plus approfondi, l’utilisation d’un modèle REQ/REP
formel de communication formel peut laisser (et laisse) des tiers dans une impasse réciproque: où l’un attend l’autre de faire une étape, ce qui ne sera jamais accompli, et moyen d'échapper à l'impasse.
Pour plus de détails illustrés et schéma FSA, voir cet article
Next, un système de basculement doit survivre à toute collision entre ses propres composants. Ainsi, il faut bien concevoir la signalisation d’état du système distribué et éviter autant que possible les dépendances sur la conception/le pas à pas/le blocage élément-FSA, sans quoi le comportement à sécurité intrinsèque n’est qu’une illusion.
Always manipulez les ressources avec précaution, ne considérez pas les composants de la signalisation/messagerie intelligente ZeroMQ comme des types de "consommables jetables". Cela pourrait être toléré dans les exemples classiques, pas dans les environnements de système de production. Vous devez toujours payer les coûts (temps, allocations de ressources/désaffectations/ramassage des ordures). Comme indiqué dans les commentaires, ne laissez jamais la création/affectation de ressources sans contrôle. while True: .socket(); .bind(); .send();
est brutalement erroné et détériore le reste de la conception.
Implémentez le modèle de pirate lazy . Créez un new socket à partir de votre contexte lorsqu'une erreur est interceptée, avant de tenter à nouveau d'envoyer le message.
La bonne solution en force brute consiste à fermer et à rouvrir le socket REQ Après une erreur
Ici est un exemple en python.
#
# Author: Daniel Lundin <dln(at)eintr(dot)org>
#
from __future__ import print_function
import zmq
REQUEST_TIMEOUT = 2500
REQUEST_RETRIES = 3
SERVER_ENDPOINT = "tcp://localhost:5555"
context = zmq.Context(1)
print("I: Connecting to server…")
client = context.socket(zmq.REQ)
client.connect(SERVER_ENDPOINT)
poll = zmq.Poller()
poll.register(client, zmq.POLLIN)
sequence = 0
retries_left = REQUEST_RETRIES
while retries_left:
sequence += 1
request = str(sequence).encode()
print("I: Sending (%s)" % request)
client.send(request)
expect_reply = True
while expect_reply:
socks = dict(poll.poll(REQUEST_TIMEOUT))
if socks.get(client) == zmq.POLLIN:
reply = client.recv()
if not reply:
break
if int(reply) == sequence:
print("I: Server replied OK (%s)" % reply)
retries_left = REQUEST_RETRIES
expect_reply = False
else:
print("E: Malformed reply from server: %s" % reply)
else:
print("W: No response from server, retrying…")
# Socket is confused. Close and remove it.
client.setsockopt(zmq.LINGER, 0)
client.close()
poll.unregister(client)
retries_left -= 1
if retries_left == 0:
print("E: Server seems to be offline, abandoning")
break
print("I: Reconnecting and resending (%s)" % request)
# Create new connection
client = context.socket(zmq.REQ)
client.connect(SERVER_ENDPOINT)
poll.register(client, zmq.POLLIN)
client.send(request)
context.term()