Do I actually need a message broker or are websockets enough

client-serverflaskmessage-queuesocket.iowebsockets

The website I am building has a real-time messaging component. The backend is built with Flask and I have integrated Flask-SocketIO to handle Websocket connections when users are on the messaging page.

My current infrastructure is pretty simple. Flask handles both HTTP requests and Websocket events. When users land on the Messages page, the client sends a GET /message_history request and then opens a socket connection.

enter image description here

When Alice sends a message to Bob, the server handles the event, checks that Alice is logged in and is allowed to talk to Bob, then stores the message in the database and finally emits the message back to both Alice and Bob, whose clients are listening for events from the server.

This works fine in development but for production I need to make changes.

Primarily, this won't work under a load-balancer. As per the Flask-SocketIO docs:

There are two requirements to use multiple Flask-SocketIO workers:

  • The load balancer must be configured to forward all HTTP requests from
    a given client always to the same worker. This is sometimes referenced
    as “sticky sessions”.

  • Since each of the servers owns only a subset of the client
    connections, a message queue such as Redis or RabbitMQ is used by the
    servers to coordinate complex operations such as broadcasting and
    rooms.

However, I don't quite understand how to implement Redis or RabbitMQ as part of my current event handlers, since the clients will not be connecting to Redis/RabbitMQ directly. The Flask server will always need to be the middleman since it needs to perform checks and store the messages in the database.

Take a look at this answer on SO:

Redis pub/sub is great in case all clients have direct access to
redis. If you have multiple node servers, one can push a message to
the others.

But if you also have clients in the browser, you need something else
to push data from a server to a client, and in this case, socket.io is
great.

Now, if you use socket.io with the Redis store, socket.io will use
Redis pub/sub under the hood to propagate messages between servers,
and servers will propagate messages to clients.


EDIT

I followed the docs: I have Redis running locally, I have installed the dependecies and monkey-patched eventlet. I ran everything and it works… ? I see that Redis is receiving "SUBSCRIBE" and "PUBLISH" events…

  1. Do I still need my PSQL database? Can I use the Redis store to fetch historic messages? What happens if the Redis instance dies?

  2. If I run this under a load-balancer, and have configured sticky sessions, does Redis (or Flask?) automagically know how to distribute the messages to the correct nodes?

Best Answer

At a high-level, in your design, the PostgreSQL database is standing in for the Redis cache and/or messaging system.

This can be made to work but you could run into scalability issues. When you use a database as a messaging system, managing the state of messages becomes problematic. For example, when you create a new message to be sent, you want to make sure that only one handler picks up that message and delivers it. This coordination is not something that DBs tend to provide by default. There are various schemes you can use but if you use a messaging platform it's an inherent feature.

Related Topic