Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using ZeroMQ to send replies to specific clients and queue if client disconnects

Tags:

zeromq

pyzmq

I'm new to ZeroMQ and trying to figure out a design issue. My scenario is that I have one or more clients sending requests to a single server. The server will process the requests, do some stuff, and send a reply to the client. There are two conditions:

  • The replies must go to the clients that sent the request.
  • If the client disconnects, the server should queue messages for a period of time so that if the client reconnects, it can receive the messages it missed.

I am having a difficult time figuring out the simplest way to implement this.

Things I've tried:

  • PUB/SUB - I could tag replies with topics to ensure only the subscribers that sent their request (with their topic as their identifier) would receive the correct reply. This takes care of the routing issue, but since the publisher is unaware of the subscribers, it knows nothing about clients that disconnect.

  • PUSH/PULL - Seems to be able to handle the message queuing issue, but looks like it won't support my plan of having messages sent to specific clients (based on their ID, for example).

  • ROUTER/DEALER - Design seemed like the solution to both, but all of the examples seem pretty complex.

My thinking right now is continuing with PUB/SUB, try to implement some sort of heartbeat on the client end (allowing the server to detect the client's presence), and when the client no longer sends a heartbeat, it will stop sending messages tagged with its topic. But that seems sub-optimal and would also involve another socket.

Are there any ideas or suggestions on any other ways I might go about implementing this? Any info would be greatly appreciated. I'm working in Python but any language is fine.

like image 534
JoshG Avatar asked Oct 31 '22 16:10

JoshG


1 Answers

To prepare the best proposition for your solution, more data about your application requirements. I have made a little research about your conditions and connnect it with my experience about ZMQ, here I present two possibilities:

1) PUSH/PULL pattern in two direction, bigger impact on scalability, but messages from server will be cached.

Server has one PULL socket to register each client and get all messages from clients. Each message should have client ID to for server knowledge where send response.

For each client - server create PUSH socket to send responses. Socket configuration was sent in register message. You can use also REQ/REP pattern for register clients (assign socket number).

Each client has own PULL socket, which configuration was sent to server in register message.

It means that server with three clients required to (example port numbers in []):

  • server: 1 x PULL[5555] socket, 3 x PUSH[5560,5561,5562] sockets (+ optional 1 X REQ[5556] socket for registrations, but I think it depends how you prepare client identity)
  • client: 1 x PUSH[5555] socket, 1 x PULL[5560|5561|5562] (one per client) (+ optional 1 X REP[5556])

You have to connect server to multiple client sockets to send responses but if client disconnects, messages will not lost. Client will get their own messages when it reconnect to their PULL socket. The disadvantage is requirements of creating few PUSH sockets on server side (number of clients).

2) PUB/SUB + PUSH/PULL or REQ/REP, static cocket configuration on server side (only 2), but server has to prepare some mechanism for retransmit or cache messages.

Server create PUB socket and PULL or REQ. Client register it identity by PULL or REQ socket. server will publish all messages to client with this identity as filter. Server use monitor() function on PUB socket to count number of connected and disconnected clients (actions: 'accept' and 'disconnect'). After 'disconnect' action server publish message to all clients to register again. For clients which not re-register, server stop publish messages.

Client create SUB socket and PUSH or REQ to register and send requests.

This solution requires maybe some cache on server side. Client could confirm each message after get it from SUB socket. It is more complicated and have to be connected with your requirement. If you just would like to know that client lost message. Client could send timestamps of last message received from server during registration. If you need guarantee that clients get all messages, you need some cache implementation. Maybe other process which subscribe all messages and delete each confirmed by client.

In this solution server with three clients required to (example port numbers in []):

  • server: 1 x PUB[5555] socket, 1 x REP or PULL[5560] socket + monitoring PUB socket
  • client: 1 x SUB[5555] socket and own identity for filter, 1 x REQ or PUSH[5560] socket

About monitoring you could read here: https://github.com/JustinTulloss/zeromq.node#monitoring (NodeJS implementation, but Python will be similar)


I think about other patterns, but I am not sure that ROUTER/DEALER or REQ/REP will cover your requirements. You should read more about patterns, because each of it is better for some solutions. Look here:

  • official ZMQ guide (a lot of examples and pictures)
  • easy ROUTER/DEALER example: http://blog.scottlogic.com/2015/03/20/ZeroMQ-Quick-Intro.html
like image 80
Michał P. Avatar answered Nov 20 '22 04:11

Michał P.