What is RabbitMQ?
The concept of messaging in the software environment is similar to the daily life processes. For example, you went for a morning coffee. After taking your order, the manager inputs it into the system. If there is no rush in the coffee shop, your order does not require to be added in a queue. However, if there are previous orders, the system puts it behind other orders. Thus, your order becomes part of the queue.
However, what if there are countless orders and the server is unable to manage all those due to a hardware issue? What to do now? In such cases, a service like RabbitMQ can prove to be the game changer. RabbitMQ will take all the orders and only forward them to the server when it can manage the workload.
Before understanding RabbitMQ, it is essential to equip yourself with the knowledge of a message broker. A message broker is an intermediary program that works on the translation of the contents of a message with the messaging protocols of both the receiver and the sender. Message brokers are used as a middleware solution for a variety of software applications.
RabbitMQ is a message broker software that is used for the queuing of messages. There are three main actors in the RabbitMQ lifecycle. First, we have a ‘publisher’ or ‘producer’. A publisher is the one who creates a message and sends it. Second, we have an ‘exchange’. Exchange receives the message with a routing key from the producer. The exchange will then save the message and store it in a queue. Third, we have a consumer. A consumer is a party for which the message was intended. A consumer can either be a third party or the publisher itself who consumes the message after getting it from the queue of the broker.
For the above example, we have used a single queue, but in real-world applications, there would be multiple queues. An exchange is connected to a queue through a binding key. The exchange will use the routing key and binding key to confirm the consumer of a message. However, it is important to note that sometimes an exchange will link a routing key with the name of a queue instead of using a binding key. There are mainly four types of exchanges: direct, topic, headers and fanout.
Whenever a message goes to a consumer, RabbitMQ makes it certain that it is received in the correct order. The queues do not let a message get lost.
RabbitMQ comes with a protocol known as AMQP (Advanced Message Queuing Protocol). AMQP helps to define three major components.
- Where should the message go?
- How will it get delivered?
- What goes in must also come out.
AMQP does not require a learning curve and can be easily programmed due to its flexibility. Thus, if a developer works with the HTTP and TCP requests and responses, they will easily adapt its protocol.
RabbitMQ supports development support for all the popular programming languages including Java, .NET, Python, PHP, JavaScript, etc.
Example
For a practical explanation, we will write a simple application in Java with RabbitMQ. The application will consist of a producer, which will send a message, as well a consumer, which will receive that message. For sending, we have a file named Send.java. You will require the following import.
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
Now, setup the class.
public class Send {
private final static String QUEUE_NAME = “hello”;
public static void main(String[] argv) throws java.io.IOException { … }}
Now we will have to link our class with the server.
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(“localhost”);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
This code helps in the abstraction of the socket connection. Now, the next step is the creation of a channel. For this purpose, you will have to define a queue.
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = “Hello World!”;
channel.basicPublish(“”, QUEUE_NAME, null, message.getBytes());
System.out.println(” [x] Sent ‘” + message + “‘”);
Lastly, we close the channel and the connection;
channel.close();
connection.close();
This ends the code for the sender.
Here is complete send java class.
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Send {
private final static String QUEUE_NAME = “hello”;
public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost(“localhost”);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); String message = “Hello World!”;
channel.basicPublish(“”, QUEUE_NAME, null, message.getBytes(“UTF-8”));
System.out.println(” [x] Sent ‘” + message + “‘”);
channel.close();
connection.close();
}
}
Now you will have to write the code for the consumer. For this purpose, create a Recv.java class. Use the following import.
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
Now we will open a connection here too.
public class Recv {
private final static String QUEUE_NAME = “hello”;
public static void main(String[] argv) throws java.io.IOException, java.lang.InterruptedException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost(“localhost”);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); System.out.println(” [*] Waiting for messages. To exit press CTRL+C”);
… }
}
Now you will have to notify the server so it can fetch the messages that are accumulating in the queue.
Consumer consumer = new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String message = new String(body, “UTF-8”);
System.out.println(” [x] Received ‘” + message + “‘”);
}};
channel.basicConsume(QUEUE_NAME, true, consumer);
Now run both the consumer and the producer, and you will have your RabbitMQ hello world application.
Complete Recv.java
import com.rabbitmq.client.*;
import java.io.IOException;
public class Recv {
private final static String QUEUE_NAME = “hello”;
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(“localhost”);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(” [*] Waiting for messages. To exit press CTRL+C”);
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, “UTF-8”);
System.out.println(” [x] Received ‘” + message + “‘”);
}
};
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
Final Thoughts
RabbitMQ has been adopted in thousands of deployment environments. It provides a significant boost in the scalability and loose coupling of applications. Today, it is by far the most popular message broker. Moreover, it also provides convenience with the cloud and also supports various message protocols, making it a desirable option for your development toolbox.