To provide massive scalability of a large messaging fabric you typically want to allow many brokers to be connected together into a network so that you can have as many clients as you wish all logically connected together - and running as many message brokers as you need based on your number of clients and network topology. If you are using client/server or hub/spoke style topology then the broker you connect to becomes a single point of failure which is another reason for wanting a network (or cluster) of brokers so that you can survive failure of any particular broker, machine or subnet. From 1.1 onwards of ActiveMQ supports networks of brokers which allows us to support distributed queues and topics across a network of brokers. This allows a client to connect to any broker in the network - and fail over to another broker if there is a failure - providing from the clients perspective a HA cluster of brokers. N.B. By default a network connection is one way only - the broker that establishes the connection passes messages to the broker(s) its connected to. From version 5.x of ActiveMQ, a network connection can be optionally enabled to be duplex, which can be useful for hub and spoke architectures, where the hub is behind a firewall etc. Configuring a network of brokersThe easiest way to configure a network of brokers is via the Xml Configuration. There are two main ways to create a network of brokers
Example with a fixed list of URIsHere is an example of using the fixed list of URIs <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://activemq.org/config/1.0"> <broker brokerName="receiver" persistent="false" useJmx="false"> <networkConnectors> <networkConnector uri="static:(tcp://localhost:62001)"/> </networkConnectors> <persistenceAdapter> <memoryPersistenceAdapter/> </persistenceAdapter> <transportConnectors> <transportConnector uri="tcp://localhost:62002"/> </transportConnectors> </broker> </beans> ActiveMQ also supports other transports than tcp to be used for the network connector such as http. Example using multicast discoveryThis example uses multicast discovery <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://activemq.org/config/1.0"> <broker name="sender" persistent="false" useJmx="false"> <networkConnectors> <networkConnector uri="multicast://default"/> </networkConnectors> <persistenceAdapter> <memoryPersistenceAdapter/> </persistenceAdapter> <transportConnectors> <transportConnector uri="tcp://localhost:0" discoveryUri="multicast://default"/> </transportConnectors> </broker> </beans> Starting network connectorsBy default, network connectors are initiated serially as part of the broker start up sequence. When some networks are slow, they prevent other networks from starting in a timely manner. Version 5.5 supports the broker attribute networkConnectorStartAsync="true" which will cause the broker to use an executor to start network connectors in parallel, asynchronous to a broker start. Static discoveryWith <networkConnectors> <networkConnector uri="static:(tcp://host1:61616,tcp://host2:61616,tcp://..)"/> </networkConnectors> There are some useful properties you can set on a static network connector for retries:
e.g. uri="static:(tcp://host1:61616,tcp://host2:61616)?maxReconnectDelay=5000&useExponentialBackOff=false" MasterSlave DiscoveryA common configuration option for a network of brokers is to establish a network bridge between a broker and an n+1 broker pair (master/slave). Typical configurations involve using the <networkConnectors> <networkConnector uri="masterslave:(tcp://host1:61616,tcp://host2:61616,tcp://..)"/> </networkConnectors> The URIs are listed in order for: MASTER,SLAVE1,SLAVE2...SLAVE The same configuration options for NetworkConnector Properties
ReliabilityNetworks of brokers do reliable store and forward of messages. If the source is durable, persistent messages on a queue or a durable topic subscription, a network will retain the durability guarantee. OrderingTotal message ordering is not preserved with networks of brokers. Total ordering works with a single consumer but a networkBridge introduces a second consumer. In addition, network bridge consumers forward messages via producer.send(..), so they go from the head of the queue on the forwarding broker to the tail of the queue on the target. If single consumer moves between networked brokers, total order may be preserved if all messages always follow the consumer but this can be difficult to guarantee with large message backlogs. When to use and not use Conduit subscriptionsActiveMQ relies on information about active consumers (subscriptions) to pass messages around the network. A broker interprets a subscription from a remote (networked) broker in the same way as it would a subscription from a local client connection and routes a copy of any relevant message to each subscription. With Topic subscriptions and with more than one remote subscription, a remote broker would interpret each message copy as valid, so when it in turns routes the messages to its own local connections, duplicates would occur. Hence default conduit behavior consolidates all matching subscription information to prevent duplicates flowing around the network. With this default behaviour, N subscriptions on a remote broker look like a single subscription to the networked broker. However - duplicate subscriptions is a useful feature to exploit if you are only using Queues. As the load balancing algorithm will attempt to share message load evenly, consumers across a network will equally share the message load only if the flag Duplex network connectorsBy default a network bridge forwards messages on demand in one direction over a single connection. When
<networkConnectors> <networkConnector name="SYSTEM1" duplex="true" uri="static:(tcp://10.x.x.x:61616)"> <dynamicallyIncludedDestinations> <topic physicalName="outgoing.System1" /> </dynamicallyIncludedDestinations> </networkConnector> <networkConnector name="SYSTEM2" duplex="true" uri="static:(tcp://10.x.x.x:61616)"> <dynamicallyIncludedDestinations> <topic physicalName="outgoing.System2"/> </dynamicallyIncludedDestinations> </networkConnector> </networkConnectors> Conduit subscriptions and consumer selectorsConduit subscriptions ignore consumer selectors on the local broker and send all messages to the remote one. Selectors are then parsed on the remote brokers before messages are dispatched to consumers. This concept could create some problems with consuming on queues using selectors in a multi-broker network. Imagine a situation when you have a producing broker forwarding messages to two receiving brokers and each of these two brokers have a consumer with different selector. Since no selectors are evaluated on the producer broker side, you can end up with all messages going to only one of the brokers, so messages with certain property will not be consumed. If you need to support this use case, please turn off Configuration PitfallsNetworks do not work as expected (they cannot dynamically respond to new consumers) if the Networks of brokers and advisoriesNetwork of brokers relies heavily on advisory messages, as they are used under the hood to express interest in new consumers on the remote end. By default, when network connector starts it defines one consumer on the following topic This is all fine and well in small networks and environments whit small number of destinations and consumers. But as things starts to grow a default model (listen to everything, share everything) won't scale well. That's why there are many ways you can use to filter destinations that will be shared between brokers. Dynamic networksLet's start with dynamically configured networks. This means that we only want to send messages to the remote broker when there's a consumer there. If we want to limit this behavior only on certain destinations we will use <networkConnector uri="static:(tcp://host)"> <dynamicallyIncludedDestinations> <queue physicalName="include.test.foo"/> <topic physicalName="include.test.bar"/> </dynamicallyIncludedDestinations> </networkConnector> In versions of ActiveMQ prior to 5.6, the broker would still use the same advisory filter and express interest in all consumers on the remote broker. The actual filtering will be done during message dispatch. This is suboptimal solution in huge networks as it creates a lot of "advisory" traffic and load on the brokers. Starting with version 5.6, the broker will automatically create an appropriate advisory filter and express interest only in dynamically included destinations. For our example it will be " In older broker versions we can achieve the same thing with a slightly more complicated configuration. The actual advisory filter that controls in which consumers we are interested is defined with the <networkConnector uri="static:(tcp://host)" destinationFilter="Queue.include.test.foo,ActiveMQ.Advisory.Consumer.Topic.include.test.bar"> <dynamicallyIncludedDestinations> <queue physicalName="include.test.foo"/> <topic physicalName="include.test.bar"/> </dynamicallyIncludedDestinations> </networkConnector> Note that first destination does not have the prefix because it's already implied. It's a bit more complicated to set and maintain, but it will work. And if you're using 5.6 or newer version of the broker just including desired destinations with This also explains why dynamic networks do not work if you turn off advisory support on the brokers. The brokers in this case cannot dynamically respond to new consumers. Pure static networksIf you wish to completely protect the broker from any influence of consumers on the remote broker, or if you wish to use the brokers as a simple proxy and forward all messages to the remote side no matter if there are consumers there or not, static networks are something you should consider. <networkConnector uri="static:(tcp://host)" staticBridge="true"> <staticallyIncludedDestinations> <queue physicalName="always.include.queue"/> </staticallyIncludedDestinations> </networkConnector> The <networkConnector uri="static:(tcp://host)" destinationFilter="NO_DESTINATION"> <staticallyIncludedDestinations> <queue physicalName="always.include.queue"/> </staticallyIncludedDestinations> </networkConnector> If configured like this, broker will try to listen for new consumers on Dynamic networks and Virtual Destinations (New for 5.13.0)As described above, a network of brokers can be configured to only send messages to a remote broker when there's a consumer on an included destination. However, let's consider some cases of how dynamic flow occurs when Virtual Destinations are in use. Virtual Destination consumers and Composite DestinationsHere is an example of two brokers networked together. The Local Broker contains the network connector configured with a Local Broker <networkConnector uri="static:(tcp://host)"> <dynamicallyIncludedDestinations> <topic physicalName="include.bar"/> </dynamicallyIncludedDestinations> </networkConnector> Remote Broker <compositeTopic name="include.bar" forwardOnly="false"> <forwardTo> <queue physicalName="include.bar.forward" /> </forwardTo> </compositeTopic > In this example, let's consider a single consumer on the Remote Broker on the queue The message is not forwarded because a consumer on the First, we need to configure the Remote Broker to send advisory messages when consumers subscribe to a destination that matches a Virtual Destination. In this case, internally a match is determined through the use of a Destination Filter that determines whether one destination forwards to another destination. To enable this, set the property Remote Broker <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://activemq.org/config/1.0"> <broker name="remoteBroker" useVirtualDestSubs="true"> ..... </broker> </beans>
Local Broker <networkConnector uri="static:(tcp://host)" useVirtualDestSubs="true"> <dynamicallyIncludedDestinations> <topic physicalName="include.bar"/> </dynamicallyIncludedDestinations> </networkConnector> Now, if a consumer comes subscribes to the queue Virtual Destination Consumers on Destination CreationNow let's consider the use case above where there is the same composite topic but no consumers on the queue. Remote Broker <compositeTopic name="include.bar" forwardOnly="false"> <forwardTo> <queue physicalName="include.bar.forward" /> </forwardTo> </compositeTopic > There is a Composite Topic configured on the Remote Broker, and the Local Broker is networked to it. Even though we have enabled
Both of these conditions are considered as emitting demand for messages to the Local Broker, despite there being no active consumers on those destinations.
Remote Broker <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://activemq.org/config/1.0"> <broker name="remoteBroker" useVirtualDestSubs="true" useVirtualDestSubsOnCreation="true"> ..... </broker> </beans> With this configuration, when the queue Composite Destination consumers and Virtual TopicsThe above examples show how to configure a Composite Destination but a Virtual Topic will also work. In the example below, a consumer on a queue for a Virtual Topic on the Remote Broker will now cause demand and messages will be sent across a network from the Local Broker. Local Broker <networkConnector uri="static:(tcp://host)"> <dynamicallyIncludedDestinations> <topic physicalName="VirtualTopic.>"/> </dynamicallyIncludedDestinations> </networkConnector> Remote Broker <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://activemq.org/config/1.0"> <broker name="remoteBroker" useVirtualDestSubs="true" > ..... </broker> </beans> Example Configuration using NetworkConnector propertiesThis part of an example configuration for a Broker <networkConnectors> <networkConnector uri="static:(tcp://localhost:61617)" name="bridge" conduitSubscriptions="true" decreaseNetworkConsumerPriority="false"> <dynamicallyIncludedDestinations> <queue physicalName="include.test.foo"/> <topic physicalName="include.test.bar"/> </dynamicallyIncludedDestinations> <excludedDestinations> <queue physicalName="exclude.test.foo"/> <topic physicalName="exclude.test.bar"/> </excludedDestinations> <staticallyIncludedDestinations> <queue physicalName="always.include.queue"/> <topic physicalName="always.include.topic"/> </staticallyIncludedDestinations> </networkConnector> </networkConnectors> Note that at the moment It is possible to have more than one network connector between two brokers. Each network connector uses one underlying transport connection, so you may wish to do this to increase throughput, or have a more flexible configuration.
<networkConnectors> <networkConnector uri="static:(tcp://localhost:61617)" name="queues_only" conduitSubscriptions="false" decreaseNetworkConsumerPriority="false"> <excludedDestinations> <topic physicalName=">"/> </excludedDestinations> </networkConnector> </networkConnectors> N.B. You can only use wildcards in the Stuck Messages (version 5.6)By default, it is not permissible for a message to be replayed back to the broker from which it came. This ensures that messages do not loop when duplex or by directional network connectors are configured. Occasionally it is desirable to allow replay for queues. Consider a scenario where a bidirectional bridge exists between a broker pair. Producers and Consumers get to randomly choose a broker using the failover transport. If one broker is restarted for maintenance, messages accumulated on that broker, that crossed the network bridge, will not be available to consumers till they reconnect to the broker. One solution to this problem is to force a client reconnect using rebalanceClusterClients. Another, is to allow replay of messages back to the origin as there is no local consumer on that broker. <destinationPolicy> <policyMap> <policyEntries> <policyEntry queue="TEST.>" enableAudit="false"> <networkBridgeFilterFactory> <conditionalNetworkBridgeFilterFactory replayWhenNoConsumers="true"/> </networkBridgeFilterFactory> </policyEntry> </policyEntries> </policyMap> </destinationPolicy> N.B.: When using Throttling a network consumerThe |