Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • Guided learning
      Receive custom learning paths powered by our AI assistant.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

Implementing Apache ActiveMQ-style broker meshes with Apache Artemis

June 30, 2021
Kevin Boone
Related topics:
JavaOpen source
Related products:
Red Hat OpenShift Container PlatformStreams for Apache Kafka

    Apache ActiveMQ and Apache Artemis (or ActiveMQ Artemis) are open source message brokers with similar functionality. Both implementations are venerable, with histories that go back to the early 2000s. However, Artemis is in some senses a more modern implementation because, ironically, it has a smaller feature set. This makes Artemis easier to maintain, which is important if you're basing a commercial product on it. The smaller feature set means a smaller overall implementation, which fits well with developing microservices.

    Early versions of Red Hat AMQ were based on ActiveMQ, but attention has shifted to Artemis in AMQ 7. ActiveMQ is not maintained as vigorously as it once was by the open source community, but at the time of writing, Amazon is still offering a message broker service based on ActiveMQ. Whether it has a long-term future, at Amazon or elsewhere, remains to be seen.

    Leaving aside ActiveMQ's complex niche features (such as message routing based on Apache Camel rules), ActiveMQ and Artemis look similar to the integrator and, in most practical applications, provide comparable throughput. However, they differ in important areas. Message distribution in the presence of multiple active brokers causes particular problems for integrators who want to move from ActiveMQ to Artemis.

    This article describes subtleties that can lead to lost messages in an Artemis active-active mesh. That architecture consists of multiple message brokers interconnected in a mesh, each broker with its own message storage, where all are simultaneously accepting messages from publishers and distributing them to subscribers. ActiveMQ and Artemis use different policies for message distribution. I will explain the differences and show a few ways to make Artemis work more like ActiveMQ in an active-active scenario.

    Configuring the Artemis broker mesh

    For simplicity, I'm assuming that the brokers in the mesh have network names like broker1, broker2, etc., and that each listens for all messaging protocols on port 61616 (this is the default for Artemis as well as ActiveMQ). The setup I describe below is for broker1, but there is a high degree of symmetry between the brokers, so it isn't hard to work out the other broker settings.

    When creating a new broker, the usual approach is to run artemis create brokerXXX to create an outline configuration. I'm assuming that you have done this initial configuration, and so only mesh-related configuration has to be added to etc/broker.xml.

    The acceptor definition

    Every Artemis broker has at least one acceptor definition that defines the TCP port and the protocols that will be accepted on that port. There's probably nothing different about this definition in a broker mesh, compared to a standalone broker. Here's an example, for a broker that accepts all wire protocols on port 61616:

    <acceptor name="artemis">tcp://0.0.0.0:61616?
       protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE/>

    In practice, an acceptor that handles multiple protocols will probably have a lot of additional configuration, but that's not really relevant here. In any case, the instance-creation step will already have created an outline entry. You'll need to change it only if you want a specific configuration, such as using different network interfaces for client and interbroker communication.

    The connectors

    Next, we need to define connectors. These are equivalent to the network connector definitions in ActiveMQ, but there is one significant difference: With Artemis, we usually define the broker itself as a connector. Here is an example:

      <connectors>
        <connector name="myself">tcp://broker1:61616</connector>
        <connector name="broker2">tcp://broker2:61616</connector>
        <connector name="broker3">tcp://broker3:61616</connector>
      </connectors>
    

    The first entry, myself, denotes the current broker with its hostname and port. Subsequent entries define the other brokers in the mesh. For symmetry, I could have given the self-referential connector the name broker1, to match the other brokers that follow. This naming approach may be useful if you have a large mesh and you want to cut and paste your configuration from one broker to another. However, sometimes it is clearer to make the self-referential connector stand out in some way. In any case, the important point is to define connectors for every broker in the mesh, including this one.

    The broker mesh

    The final vital piece of configuration assembles the various broker connectors into a mesh. Artemis provides various discovery mechanisms by which brokers can find one another in the network. However, if you're more familiar with ActiveMQ, you're probably used to specifying the mesh members explicitly. The following example shows how to do that, for the connectors listed in the configuration just shown. Note that I'm referring to this broker itself as myself, to match the previous connector definition. It would be a mistake to list the current broker as a cluster connection, which is why I prefer to use a distinctive name.

     <cluster-connections>
        <cluster-connection name="my_mesh">
          <connector-ref>myself</connector-ref>
          <message-load-balancing>ON_DEMAND</message-load-balancing>
          <static-connectors>
            <connector-ref>broker2</connector-ref>
            <connector-ref>broker3</connector-ref>
          </static-connectors>
        </cluster-connection>
      </cluster-connections>

    Note: I'll have more to say about message-load-balancing later.

    You'll probably want to configure your clients to know about the mesh, as well. Again, Artemis provides a number of discovery mechanisms, allowing clients to determine the network topology without additional configuration. These don't work with all wire protocols (notably, there is no discovery mechanism for Advanced Message Queuing Protocol), and ActiveMQ users are probably familiar with configuring the client's connection targets explicitly. The usual mechanism is to list all the brokers in the mesh in the client's connection URI.

    Why the Artemis configuration isn't (yet) like ActiveMQ

    With the configuration in the previous section, you should have a working mesh. That is, you should be able to connect consumers to all the nodes, produce messages to any node, and have them routed to the appropriate consumer. However, this mesh won't behave exactly like ActiveMQ, because Artemis mesh operation is not governed by client demand.

    Forwarding behavior

    In ActiveMQ, network connectors are described as "demand forwarding." This means that messages are accepted on a particular broker and remain there until a particular client requests them. If there are no clients for a particular queue, messages remain on the original broker until that situation changes.

    On Artemis, forwarding behavior is controlled by the brokers, and is only loosely associated with client load. In the previous section's configuration, I set message-load-balancing=ON_DEMAND. This instructs the brokers not to forward messages for specific queues to brokers where there are, at present, no consumers for those queues. So if there are no consumers connected at all, the routing behavior is similar to that of ActiveMQ: Messages will accumulate on the broker that originally received them. If I had set message-load-balancing=STRICT, the receiving broker would have divided the messages evenly between the brokers that defined that queue. With this configuration, the presence or absence of clients should be irrelevant ... except it isn't quite that simple, and the complications are sometimes important.

    How the message queue is defined

    Even with STRICT load balancing, brokers won't forward messages to other brokers that don't know about the queue. If queues are administratively defined, all brokers know about all queues and accept messages for them in STRICT mode. If the queues are auto-created by clients, and there are no clients for a specific queue, a producer on broker1 could send a message for a queue that was not known on broker2. As a result, messages would never be forwarded. In short: It makes a difference whether a queue is defined administratively or auto-created. There is no such difference in message distribution in ActiveMQ, because it is driven by client demand.

    Even with ON_DEMAND load balancing, Artemis's behavior is not the same as ActiveMQ's. A particular difference is that message distribution decisions are made when the message arrives. It is at that point that the broker sees what clients are connected and routes the message as it deems appropriate. If there are no clients for a specific queue at that time, the message will not be routed.

    What this means is that if a client that is connected to broker1 goes down for some reason, and then reconnects, it will not receive any of the messages that came in the meantime. Even if there are no other clients for that queue on any other broker, the message will not be routed from its original location. It's too late—the routing decision has already been made.

    This is a particular problem for broker installations that are behind a load balancer or similar proxy. There's usually no way of knowing which broker a client will ultimately connect to because the load balancer will make that decision. But if a client has the bad fortune to get connected to a broker that has never hosted that client before, no messages that came earlier will be routed to it, even if it subscribes to a queue that has messages on some other broker. To fix this problem, we need message redistribution.

    Message redistribution in Artemis

    ActiveMQ has no need for a message redistribution mechanism, because all message flows over the network connectors are coordinated by client demand. As we've seen, this is not the case for Artemis, where all message distribution is controlled by the brokers. In the usual run of events, distribution decisions are made when messages arrive, and they are irrevocable.

    Artemis does have a way to redistribute messages after that point, but it is not enabled by default. The relevant setting is made on a specific address, or group of addresses, like this:

     <address-setting match="#">
        <redistribution-delay>1000</redistribution-delay>
        ...
      </address-setting>

    The value supplied for redistribution-delay is in units of milliseconds. This value is the length of time for which a broker will leave messages on a specific address that has no consumer, before sending them somewhere else. The default value is -1, meaning "do not redistribute.""

    A redistribution delay of seconds or minutes, rather than milliseconds, probably creates less load on the broker and the network. In short, if you set an ON_DEMAND load-balancing policy, and enable message redistribution with a relatively short delay, the broker mesh will largely look to clients like an ActiveMQ mesh.

    Why the Artemis configuration still isn't (exactly) like ActiveMQ's

    We have started to solve the problem of lost messages on Artemis. There are a number of subtle differences between Artemis and ActiveMQ, however, and it's impossible to get exactly the same behavior that ActiveMQ implements.

    Message selectors

    A particular problem involves message selectors. If a client subscribes to a queue using a selector, it expects to receive only messages that match the selector. But what happens if different clients subscribe to the same queue, with different selectors, on different brokers? This is a rather specific problem, but it does come up. Artemis forwards messages according to whether there are consumers, not according to whether there are selectors. So there's every chance that messages will get forwarded to a broker whose consumers will not match the selector. These messages will never be consumed.

    This isn't specifically an Artemis problem: Using selectors is somewhat problematic with a broker mesh, regardless of the implementation. Using selectors with a mesh isn't entirely robust on ActiveMQ, either: The broker has to maintain a "selector cache" to keep track of which selectors are active on which queues. Because it's impossible for the broker to know when clients come and go, the selector cache has to maintain tracking data for an extended period of time—perhaps indefinitely. This creates a memory burden, and as a result, there are different selector cache implementations available with different properties.

    Artemis does not use selector caches, because it side-steps the issue of selector handling altogether. Unless your clients are configured to consume from all brokers concurrently (which isn't a bad idea in many applications), it's just not safe to use selectors.

    Message grouping

    There are a number of other broker features that don't work properly in a mesh, and don't work properly with ActiveMQ, either. The most troublesome is message grouping, which doesn't work at all in an Artemis mesh. It works partially with ActiveMQ, but isn't robust in the event of a client or broker outage. "Exclusive consumers" are also problematic on both brokers.

    Recognizing the limitations described in this section, Red Hat is working on enhancements to Artemis that will allow brokers to re-route client connections to the brokers that are best placed to handle them. The work required is extensive because each of the various wire protocols that Artemis supports has its own way of dealing with dynamic load balancing.

    Summary

    In a broker mesh, Artemis uses a completely different strategy for message distribution from ActiveMQ. Understanding how Artemis works in this respect should go a long way to determining what changes need to be made to move from ActiveMQ to Artemis.

    In particular, use the ON_DEMAND load-balancing policy, and be sure to enable message redistribution. Some tuning may be needed to find the best redistribution delay for a particular application.

    Last updated: October 8, 2024

    Related Posts

    • Architectural messaging solutions with Apache ActiveMQ Artemis

    • Using the STOMP Protocol with Apache ActiveMQ Artemis Broker

    • Deploying the Mosquitto MQTT message broker on Red Hat OpenShift, Part 1

    Recent Posts

    • Debugging image mode with Red Hat OpenShift 4.20: A practical guide

    • EvalHub: Because "looks good to me" isn't a benchmark

    • SQL Server HA on RHEL: Meet Pacemaker HA Agent v2 (tech preview)

    • Deploy with confidence: Continuous integration and continuous delivery for agentic AI

    • Every layer counts: Defense in depth for AI agents with Red Hat AI

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer tools
    • Interactive tutorials
    • API catalog

    Quicklinks

    • Learning resources
    • E-books
    • Cheat sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site status dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2026 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Chat Support

    Please log in with your Red Hat account to access chat support.