Microservice + RabbitMQ application - 2

In the previous post, i have explained that we will integrate RabbitMQ on top of our existing microservice architecture. In this post, we will dig deeper into RabbitMQ and investigate it. We will look into what is Rabbitmq, what can it do and how can it be installed and ran. Then we will see what are the exchange types that lies at the base of these message brokers. And we will end this post with a brief comparison with other popular message broker tools. This post is going to be a boring non-coding one :) Let's keep the architecture of the system here.

What is RabbitMQ, what are the important features

There is a protocol called JMS (Java Messaging Service) in the JavaEE ecosystem. Back in the days, the enterprise applications were using implementations of this protocol to communicate with each other. Just like using Jersey implementation for http protocols in restful web services. Those implementations were limited and those monolithic applications didn't need that much of a messaging infrastructure. Over time, restful web services, web 2.0 and then microservices have been improved. Therefore he messaging between these small modular applications became more necessary. The long running asynchronous operations have evemerged when these systems grow larger. This trend turned JMS into AMQP (Advanced Message Queuing Protocol) for messaging and products of this protocol started emerging.

That is why we have lots of message brokers today. One of these brokers is RabbitMQ. It has upgraded to version 2.0.0 and supported amqp 0.9.1 and became a mature message broker. It shows that rabbitmq has the basic mechanisms for message transportaion among the parties that a message broker must have, by conforming to this protocol. But as i have mentioned in the fist post, it doesn't just stop there and adds extra features. If you wish to know about all the version history, you can take a look at this.

Briefly, rabbitmq receives messages from various sources and transports them to various destinations with the help of its own listener APIs, by implementing AMQP. That means we have apis besides rabbitmq. So rabbitmq is an application that runs as a service on a server. This service listens to a certain port and operates on the received messages, in other words, payloads. This application is written in Erlang language. That is why you must install erlang library on your computer first to install rabbitmq.

You can download RabbitMQ here. I was able to use the prebuilt installer to install but in some situations you might have to install erlang first. There is also guidance on how to install it on Linux in the downloads page. If you are going to install erlang separately, you might encounter compatibility issues. There is a conformity matrix of erlang and rabbitmq here. So beware. After the installation, you must see a service called RabbitMQ in the running services list of your operating system.

What are the pros and cons

Since we don't have anything to do with rabbitmq now, let's just keep it running and look at the tool itself. I have mentioned that rabbitmq is able to do a lot of things. There is load balancing, resiliency, different queue structures with their own spesific features, monitoring, backup and restoring, high availability, authorization and authentication, logging... That is a nice list isn't it :) There is even more. The publisher and consumer apis are written in 11 languages. They are Python, Java, Ruby, PHP, C#, JavaScript, Go, Elixir, Objective-C, Swift, Spring AMQP. These are the most important pros i guess. Overall, having this much features and being mature as production ready gives you enough assurance. There is also clear documentation and samples. What else would you want.

All these pros sounds nice but it also breeds some of the cons. If you want to properly utilise rabbitmq, you need a whole new expertise. Because it is a full fledged product. Also you might witness different identities and roles given to rabbitmq when you are searching for a solution for your problems on the internet. For example, you may see a software company with lazy developers tries to shorten the codes and even misuses the microservices and puts a giant rabbitmq in the center of the whole system. You may also see the same problems caused by very different reasons for some people. Or you may not be able to find a proper explanation for your specific case or unawareness. These all can sharpen the learning curve and can make the trouble shooting harder. Moreover, it doesn't mean you are using the rabbitmq the right way by just deciding to use it. Think of it like a car with lots of equipments, there is a right way to properly use it.

How can load balancing and error handling work

I have mentioned that if you are working with microservices, you must somehow provide load balance, error handling (fault tolerance) and resiliency in your system. 2 of these 3 concepts (load balancing, resiliency) were provided with eureka (ribbon) + gateway (resilience4J) duo. We have handled error handling and transaction management somehow in the MVC application. All this was due to us writing the codes ourselves. If we have had used existing tools, we would have been left to the mercy of those tools :)

Now if you take a look at the schema at the top, all of the communication between the MVC app and the mail service is going through RabbitMQ. Therefore it has to provide these 3 important concepts somehow. I don't have much deeper knowledge about rabbitmq but let me briefly mention some important aspects so that you can find the answers to your questions a little.

You have couple of options for load balancing with RabbitMQ. You can multiple the mail service and therefore the rabbit listeners. I think they can fetch the messages in their corresponding queues. But this doesn't exactly reduce the load on the rabbitmq queues and they might still end up queueing thousands of messages. Even though queues are mostly used for asynchronous operations, it doesn't make much sense to have lots of messages waiting in the queues. You can still multiply the listener services though, it is up to you.

There is another solution of running multiple rabbitmq instances for Load balancing and putting another load balancer in front of them. I can't say which solution is better or worse. One has to know the system you are designing and deep features of rabbitmq to know this. Still, putting a load balancer behind a tools with load balancing features would kinda be pointless.

RabbitMQ has nodes inside it. You can add or remove these nodes that has exchanges and queues inside, just to avoid using a different tool for load balancing. This kind of imitates having more than one rabbitmq instance running. Of course you can also try multiplying listener methods on top of this. This operation is called clustering and there is a very detailed documentation about it in the official rabbitmq documentation here.

In order to provide resiliency and fault tolerance with RabbitMQ, the system must be able to recover when it is crashed or messages couldn't delivered. They have also thought about this too. RabbitMQ transfers these messages to another queue instead of letting them block the queues. There are timeout or retry settings in this operation too. It can also work with queue backups and continue working if one of them explodes. Message delivery can be one way or it can expect a return value too. All the messages that are delivered returns the acknowledgement information to rabbitmq. That is how rabbitmq is able to transfer messages to dead letter queues upon errors.

As you can see, we have been able to provide eureka and gateway functionalities with one tool in our microservice architecture. Of course i think maintaining this system with this much features would be difficult but we will dive into philosophy in the last post. There is exchange logics in the core of this whole system for conveying messages. You will have to write the publisher and consumer methods upon determining what kind of exchange logic are you going to use. So this desicion is critical.

What are exchange types

I have said AMQP 0.9.1 before and it basically determines the types of exchange methods. There are more details about it here. There are 4 fundamental exhange types. Direct, topic, fanout and headers exhange. I don't want to crowd this post with images of each of them, so you can refer to this article.

The exchange type, queue and the routing key are 3 main concepts of rabbitmq mechanism. You must indicate the exchange name to rabbitmq to send a message, since there can be multiple exchanges of the same type. It decides which queue or queues the message will go according to the routing key, by the rules that exchange method dictates. I think you need an exchange to be able to create a queue here. This is why exchange types are created.

Fanout exchange delivers the messages to all the queues bound to it, regardless of any routing keys. Direct exchange transfers the message to the related queue with the exact match ot the routing key that the publisher sends. For example, if you have a queue route like "email.receipt", the messages that has the exact same match "email.receipt" will be put into this queue. Headers exchange is kind of based on http headers. Tou can write conditions regarding the values in the message headers and re-route the messages.

Lastly, i think the topic exchange is probably the most popular of all. It can transfer the messages that contains with a routing key or starts with a routing key to certain queues. For example, if you have an expression for routing key like "email.*", the messages with "email.receipt" or "email.cancelation" routing keys will go to these queues. There is a regular expression logic working here. There is a cute little simulation for rabbitmq if you want to experiment on these exchange types here.

Of course you need to thoroughly think about what exchange type are you going to use. If you change the routing keys in the future, it would be a pain in the butt to find which messages are going where, if it is not documented. Only you can determine which exchange type is suitable for youe own system. There is no superiority among these methods but they have their own pros and cons for your system. Since we have become rabbitmq fanboys, let's see the big alternatives.

What are the alternatives

Even though i don't have detailed information about message brokers, stackshare.io provides lots of information about them. It looks like Kafka has more professional features and use cases compared to rabbitmq. It works with streams too and thus, able to handle big amount of data. Azure service bus and Amazon SQS can work serverless and naturally they have geographical options too. Since Azure service bus is based on .net framework, it would be a lot easier to use it in .net projects. By the way, they say rabbitmq can be a bit slow compared to the other tools but i don't think you would notice it unless you are working with high volume of data. I think IBM MQ is one of the biggest non-cloud message brokers and it is probably a bit expensive. It is distributed with VM or a container package if you wish. Not like installing erlang first and rabbitmq later. And all the message broker alternatives for rabbitmq is here if you would like to dig more.

Why this much about RabbitMQ?

Message queues and brokers are one of the most popular concepts these days and there is a big hype around them. I have witnessed companies deciding to use a message broker tool just because other are using it. A microservice application does not always have to use message brokers. When you are developing microservices, all the small pieces of the system affects the other parts even it's just a little bit. After all, they are all communicating with each other somehow. That's why you have to analyze your system end-to-end before using and depending on these message brokers that has years of development and their own expertise fields. In this post, we have investigated questions like why and how we can use rabbitmq. We have looked at the alternatives to not to regret our decision. Now we will send messages to rabbitmq and open the management console. See you at the next post :)


Leave a comment