ActiveMQ vs RabbitMQ: A comparison

Apache ActiveMQ Artemis and RabbitMQ are both open-source message brokers that provide a way for applications to communicate asynchronously and reliably. However, there are some key differences between the two platforms. In this article, we will compare them and see which are the common use cases for both messaging brokers.

Comparison of Features

Let’s begin by comparing Message Protocols:

  • ActiveMQ Artemis supports a wider range of messaging protocols than RabbitMQ, including AMQP, MQTT, STOMP, OpenWire, and JMS. This makes it a good choice for applications that need to communicate with a variety of clients.
  • RabbitMQ, on the other hand, is primarily focused on AMQP, but it also supports MQTT and STOMP. It is worth mentioning that RabbitMQ does not support out of the box JMS messaging. Although you can install a JMS Plugin to enable JMS support to its clients.

With regards to Routing and Exchange of Messages:

  • ArtemisMQ: Implements the concept of “address” for routing messages, and it supports various types of routing, including anycast and multicast. An address in Apache Artemis is a logical destination for the message.
  • RabbitMQ: Implements the concept of “exchange” . An exchange in RabbitMQ is a message routing component that determines how messages are distributed to queues. Exchanges define the routing rules for messages based on their routing keys, allowing for different exchange types such as direct, fanout, topic, and headers.

To understand better, let’s compare a simple JMS Client for both messaging brokers.

Comparing Messaging Clients

To see how each broker handles routing and exchanges of messages we will show a sample JMS Client for each broker. Here is a sample RabbitMQ Client:

import com.rabbitmq.client.*;

public class RabbitMQExample {

    private final static String EXCHANGE_NAME = "exampleExchange";
    private final static String ROUTING_KEY = "exampleRoutingKey";
    private final static String QUEUE_NAME = "exampleQueue";

    public static void main(String[] argv) throws Exception {
        // Create a connection factory
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");

        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {

            // Declare an exchange
            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);

            // Declare a queue
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);

            // Bind the queue to the exchange with a routing key
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);

            // Publish a message to the exchange with the routing key
            String message = "Hello RabbitMQ!";
            channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, null, message.getBytes("UTF-8"));
            System.out.println(" [x] Sent '" + message + "'");

            // Create a consumer
            DeliverCallback deliverCallback = (consumerTag, delivery) -> {
                String receivedMessage = new String(delivery.getBody(), "UTF-8");
                System.out.println(" [x] Received '" + receivedMessage + "'");
            };

            // Consume messages from the queue
            channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
        }
    }
}

In this example:

  • We declare an exchange (EXCHANGE_NAME) in RabbitMQ. An exchange in RabbitMQ is conceptually similar to an address in Artemis.
  • We declare a queue (QUEUE_NAME) and bind it to the exchange using a routing key (ROUTING_KEY). This is analogous to creating an address and associating queues with it in Artemis.
  • We publish a message to the exchange with a specified routing key.
  • We consume messages from the queue. Messages sent to the exchange with the matching routing key will be routed to the queue.

Here is an equivalent Artemis JMS Client:

import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
import org.apache.activemq.artemis.api.core.client.ClientMessage;
import org.apache.activemq.artemis.api.core.client.ClientProducer;
import org.apache.activemq.artemis.api.core.client.ClientSession;
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;

import java.util.HashMap;
import java.util.Map;

public class ArtemisExample {

    public static void main(String[] args) throws Exception {
        // Create the transport configuration
        TransportConfiguration transportConfiguration = new TransportConfiguration(
                NettyConnectorFactory.class.getName());

        // Create a map of properties for the address settings
        Map<String, Object> addressSettings = new HashMap<>();
        addressSettings.put("anycast", true); // Use anycast routing type

        // Create the client session factory
        ClientSessionFactory sessionFactory = org.apache.activemq.artemis.api.core.client.ServerLocatorImpl
                .newBuilder()
                .addTransportConfiguration(transportConfiguration)
                .setAckBatchSize(0)
                .setAddressSettings(addressSettings)
                .createSessionFactory();

        // Create a session
        try (ClientSession session = sessionFactory.createSession()) {
            // Create an address
            session.createAddress("exampleAddress", "anycast");

            // Create a producer
            ClientProducer producer = session.createProducer("exampleAddress");

            // Send a message to the address
            ClientMessage message = session.createMessage(true);
            message.getBodyBuffer().writeString("Hello Artemis!");
            producer.send(message);

            // Create a consumer
            ClientConsumer consumer = session.createConsumer("exampleAddress");

            // Receive the message from the address
            session.start();
            ClientMessage receivedMessage = consumer.receive();
            System.out.println("Received: " + receivedMessage.getBodyBuffer().readString());
        }
    }
}

In this example, “exampleAddress” is the Artemis address, and the routing type is set to “anycast.” Messages sent to this address will follow anycast semantics, similar to point-to-point messaging in RabbitMQ.

Comparing Enterprise support

Both Artemis MQ and RabbitMQ have Enterprise support, besides the Community Edition.

VMware offers a range of commercial offerings for RabbitMQ. This includes a distribution called VMware RabbitMQ that deploys on Kubernetes or your container Runtime, a version that deploys in VMware Tanzu Application Service as well as OVA and OCI versions.

On the other hand, there are several companies providing Enterprise support for Artemis MQ. Namely, Red Hat offers AMQ Broker, a supported distribution of Apache ActiveMQ that includes enterprise developer and production support as well as training and consultancy for enterprise deployments.

Summary and recap

In conclusion, the following table compares side-by-side the most important differences or concepts between RabbitMQ and Artemis MQ:

Feature/AspectRabbitMQApache Artemis
Conceptual PurposeAn exchange routes messages to queues based on routing keys and exchange types.An address is a logical destination to which messages are sent, routing them to one or more queues.
Routing SemanticsSupports direct, fanout, topic, and headers exchanges with different routing semantics.Supports anycast and multicast addresses for different routing behaviors.
Exchange/Address TypesDirect Exchange: Routes based on routing key. <br> Fanout Exchange: Routes to all bound queues. <br> Topic Exchange: Routes based on wildcard matches. <br> Headers Exchange: Routes based on header attributes.Anycast Address: Routes to exactly one consumer. <br> Multicast Address: Routes to all subscribing consumers.
TerminologyProducers publish messages to exchanges. <br> Queues are bound to exchanges.Producers send messages to addresses. <br> Queues are associated with addresses.
Dynamic vs. StaticExchanges are often created and configured statically.Addresses can be dynamically created during runtime.
Message Broker SystemRabbitMQ is a widely used open-source message broker.Apache Artemis is an open-source messaging system, often used as a message broker.
Protocols SupportedSupports AMQP (Advanced Message Queuing Protocol), MQTT, STOMP, and more.Supports AMQP, OpenWire, STOMP, MQTT, HornetQ Core Protocol, and more.
Clustering SupportSupports clustering for high availability and scalability.Supports clustering with features like live/backup, shared-store, and broadcast groups for scalability and fault tolerance.