RabbitMQ Research – Study Notes for System Design Interviews

I recently had a system design interview where I showed a poor understanding of message queue services. In an effort to learn from that experience, I’d like to do some form of a deep dive into RabbitMQ which I believe would have been the optimal service to use for the question I was asked.

RabbitMQ is a message broker or queue manager. We all know about queues as a general data structure, but a message queue is a service that offers this kind of functionality at the infrastructure level. Applications can connect to message queues in order to transfer a message or messages.

A message queue stores messages (the contents of the message is defined by the application that is sending messages to the queue, it can be anything!) that are later taken off the queue by a receiving application.

In RabbitMQ, messages are not published straight to a queue. They are first published to an exchange which allows support for multiple queues.

In the question I was given, I had to build a service that would send 100-200 million emails per day. Emails were sent with an API that had a few millisecond response time. Let’s say we round that up to 10ms to account for variances and extra processing we may need to do. It also gives us some room to grow:

  • 200 million / 24 hours = 8.33 million emails per hour
  • One queue can send an email every 10ms:
    • (60 minutes = 3600 seconds) / (10ms = 0.01 seconds) = 360,000 emails per hour on one queue
  • 360,000 / 8.33 = 23 queues required with even distribution
  • Let’s round up to 30 to give us even more breathing room

This is where this becomes my personal notes. I’m not sure why I am writing this here but maybe it will be helpful to someone else. Just know I am more or less experimenting here — this may be crazily incorrect!

Is it reasonable to have 30 queues for an application of this size? The first thing I see here is that each message queue in RabbitMQ can hold about 50,000 messages at one time. This would actually mesh with what I came up with because I built a custom scheduler. This can certainly make sure we don’t dump all of our messages in the queue at once.

It does seem like RabbitMQ can handle potentially thousands of queues that an exchange can route messages to.

It looks like others have come to a similar solution for a similar type of system design question. Maybe I didn’t do as poorly as I thought! Although I was not able to get into this level of specificity about individual message broker services, I definitely chose the right general tool and I think I was on the right path.

Round robin dispatching

Another piece of this that I feel is important is being able to dispatch messages to our 30+ queues in a round robin format. One of the issues with studying system design questions as a mid level engineer is that you likely don’t have intensive experience developing all of the different infrastructure pieces and tools that are helpful to answer these questions satisfactorily.

Frankly, I’ve never implemented a message queue in production. For this, I wanted to get a sense of what some of this code would look like. Here is what this looks like in Python. This is a perfect example of what I’m talking about — I was hoping to see some code where it specifies the distribution approach, but RabbitMQ ┬ánaturally defaults to round robin! I think trying to look at at least some code for things I might mention in system design interviews is a great approach to improving my performance in these.

Here’s what some code would look like if you wanted to use a fanout instead, where every message goes to all queues.

channel.exchange_declare(exchange='logs',
                         exchange_type='fanout')

Update: I don’t know if that source is correct for the round robin dispatching. Exchanges are stateless, so we may require 30 consumer nodes (what populates the queue), 30 exchanges, and 30 queues, and our scheduler node would be responsible for segmenting these requests.

Leave a Reply

Your email address will not be published. Required fields are marked *