http://git-wip-us.apache.org/repos/asf/activemq-6/blob/4245a6b4/docs/user-manual/en/architecture.xml ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/architecture.xml b/docs/user-manual/en/architecture.xml deleted file mode 100644 index ea21b47..0000000 --- a/docs/user-manual/en/architecture.xml +++ /dev/null @@ -1,151 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- ============================================================================= --> -<!-- Licensed to the Apache Software Foundation (ASF) under one or more --> -<!-- contributor license agreements. See the NOTICE file distributed with --> -<!-- this work for additional information regarding copyright ownership. --> -<!-- The ASF licenses this file to You under the Apache License, Version 2.0 --> -<!-- (the "License"); you may not use this file except in compliance with --> -<!-- the License. You may obtain a copy of the License at --> -<!-- --> -<!-- http://www.apache.org/licenses/LICENSE-2.0 --> -<!-- --> -<!-- Unless required by applicable law or agreed to in writing, software --> -<!-- distributed under the License is distributed on an "AS IS" BASIS, --> -<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --> -<!-- See the License for the specific language governing permissions and --> -<!-- limitations under the License. --> -<!-- ============================================================================= --> - -<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ -<!ENTITY % BOOK_ENTITIES SYSTEM "ActiveMQ_User_Manual.ent"> -%BOOK_ENTITIES; -]> -<chapter id="architecture"> - <title>Architecture</title> - <para>In this section we will give an overview of the ActiveMQ high level architecture.</para> - <section> - <title>Core Architecture</title> - <para>ActiveMQ core is designed simply as set of Plain Old Java Objects (POJOs) - we hope you - like its clean-cut design.</para> - <para>We've also designed it to have as few dependencies on external jars as possible. In - fact, ActiveMQ core has only one jar dependency, netty.jar, - other than the standard JDK classes! This is because we use some of the netty buffer classes - internally.</para> - <para>This allows ActiveMQ to be easily embedded in your own project, or instantiated in any - dependency injection framework such as JBoss Microcontainer, Spring or Google - Guice.</para> - <para>Each ActiveMQ server has its own ultra high performance persistent journal, which it - uses for message and other persistence.</para> - <para>Using a high performance journal allows outrageous persistence message performance, - something not achievable when using a relational database for persistence.</para> - <para>ActiveMQ clients, potentially on different physical machines interact with the ActiveMQ - server. ActiveMQ currently provides two APIs for messaging at the client side:</para> - <para> - <orderedlist> - <listitem> - <para>Core client API. This is a simple intuitive Java API that allows the full - set of messaging functionality without some of the complexities of - JMS.</para> - </listitem> - <listitem> - <para>JMS client API. The standard JMS API is available at the client - side.</para> - </listitem> - </orderedlist> - </para> - <para>JMS semantics are implemented by a thin JMS facade layer on the client side.</para> - <para>The ActiveMQ server does not speak JMS and in fact does not know anything about JMS, - it is a protocol agnostic messaging server designed to be used with multiple different - protocols.</para> - <para>When a user uses the JMS API on the client side, all JMS interactions are translated - into operations on the ActiveMQ core client API before being transferred over the wire - using the ActiveMQ wire format.</para> - <para>The server always just deals with core API interactions.</para> - <para>A schematic illustrating this relationship is shown in figure 3.1 below:</para> - <para> - <graphic fileref="images/architecture1.jpg" align="center"/> - </para> - <para>Figure 3.1 shows two user applications interacting with a ActiveMQ server. User - Application 1 is using the JMS API, while User Application 2 is using the core client - API directly.</para> - <para>You can see from the diagram that the JMS API is implemented by a thin facade layer on - the client side.</para> - </section> - <section> - <title>ActiveMQ embedded in your own application</title> - <para>ActiveMQ core is designed as a set of simple POJOs so if you have an application that - requires messaging functionality internally but you don't want to expose that as a - ActiveMQ server you can directly instantiate and embed ActiveMQ servers in your own - application.</para> - <para>For more information on embedding ActiveMQ, see <xref linkend="embedding-activemq" - />.</para> - </section> - <section> - <title>ActiveMQ integrated with a JEE application server</title> - <para>ActiveMQ provides its own fully functional Java Connector Architecture (JCA) adaptor - which enables it to be integrated easily into any JEE compliant application server or - servlet engine.</para> - <para>JEE application servers provide Message Driven Beans (MDBs), which are a special type - of Enterprise Java Beans (EJBs) that can process messages from sources such as JMS - systems or mail systems.</para> - <para>Probably the most common use of an MDB is to consume messages from a JMS messaging - system.</para> - <para>According to the JEE specification, a JEE application server uses a JCA adapter to - integrate with a JMS messaging system so it can consume messages for MDBs.</para> - <para>However, the JCA adapter is not only used by the JEE application server for <emphasis - role="italic">consuming</emphasis> messages via MDBs, it is also used when sending - message to the JMS messaging system e.g. from inside an EJB or servlet.</para> - <para>When integrating with a JMS messaging system from inside a JEE application server it - is always recommended that this is done via a JCA adaptor. In fact, communicating with a - JMS messaging system directly, without using JCA would be illegal according to the JEE - specification.</para> - <para>The application server's JCA service provides extra functionality such as connection - pooling and automatic transaction enlistment, which are desirable when using messaging, - say, from inside an EJB. It is possible to talk to a JMS messaging system directly from - an EJB, MDB or servlet without going through a JCA adapter, but this is not recommended - since you will not be able to take advantage of the JCA features, such as caching of JMS - sessions, which can result in poor performance.</para> - <para>Figure 3.2 below shows a JEE application server integrating with a ActiveMQ server via - the ActiveMQ JCA adaptor. Note that all communication between EJB sessions or entity - beans and Message Driven beans go through the adaptor and not directly to - ActiveMQ.</para> - <para>The large arrow with the prohibited sign shows an EJB session bean talking directly to - the ActiveMQ server. This is not recommended as you'll most likely end up creating a new - connection and session every time you want to interact from the EJB, which is an - anti-pattern.</para> - <para> - <graphic fileref="images/architecture2.jpg"/> - </para> - <para>For more information on using the JCA adaptor, please see <xref - linkend="appserver-integration"/>.</para> - </section> - <section> - <title>ActiveMQ stand-alone server</title> - <para>ActiveMQ can also be deployed as a stand-alone server. This means a fully independent - messaging server not dependent on a JEE application server.</para> - <para>The standard stand-alone messaging server configuration comprises a core messaging - server, a JMS service and a JNDI service.</para> - <para>The role of the JMS Service is to deploy any JMS Queue, Topic and ConnectionFactory - instances from any server side <literal>activemq-jms.xml</literal> configuration files. - It also provides a simple management API for creating and destroying Queues, Topics and - ConnectionFactory instances which can be accessed via JMX or the connection. It is a - separate service to the ActiveMQ core server, since the core server is JMS agnostic. If - you don't want to deploy any JMS Queue, Topic or ConnectionFactory instances via server - side XML configuration and don't require a JMS management API on the server side then - you can disable this service.</para> - <para>We also include a JNDI server since JNDI is a common requirement when using JMS to - lookup Queues, Topics and ConnectionFactory instances. If you do not require JNDI then - this service can also be disabled. ActiveMQ allows you to programmatically create JMS and - core objects directly on the client side as opposed to looking them up from JNDI, so a - JNDI server is not always a requirement.</para> - <para>The stand-alone server configuration uses JBoss Microcontainer to instantiate and - enforce dependencies between the components. JBoss Microcontainer is a very lightweight - POJO bootstrapper.</para> - <para>The stand-alone server architecture is shown in figure 3.3 below:</para> - <para> - <graphic fileref="images/architecture3.jpg"/> - </para> - <para>For more information on server configuration files see <xref - linkend="server.configuration"/>. $ </para> - </section> -</chapter>
http://git-wip-us.apache.org/repos/asf/activemq-6/blob/4245a6b4/docs/user-manual/en/book.json ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/book.json b/docs/user-manual/en/book.json new file mode 100644 index 0000000..7469213 --- /dev/null +++ b/docs/user-manual/en/book.json @@ -0,0 +1,12 @@ +{ + "title": "ActiveMQ Documentation", + "description": "ActiveMQ User Guide and Reference Documentation", + "github": "apache/activemq-6", + "githubHost": "https://github.com/", + + "links": { + "home": "http://activemq.apache.org/", + "issues": "http://activemq.apache.org/", + "contribute": "http://activemq.apache.org/contributing.html" + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/4245a6b4/docs/user-manual/en/client-classpath.md ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/client-classpath.md b/docs/user-manual/en/client-classpath.md new file mode 100644 index 0000000..7142958 --- /dev/null +++ b/docs/user-manual/en/client-classpath.md @@ -0,0 +1,32 @@ +The Client Classpath +==================== + +ActiveMQ requires several jars on the *Client Classpath* depending on +whether the client uses ActiveMQ Core API, JMS, and JNDI. + +> **Warning** +> +> All the jars mentioned here can be found in the `lib` directory of the +> ActiveMQ distribution. Be sure you only use the jars from the correct +> version of the release, you *must not* mix and match versions of jars +> from different ActiveMQ versions. Mixing and matching different jar +> versions may cause subtle errors and failures to occur. + +ActiveMQ Core Client +==================== + +If you are using just a pure ActiveMQ Core client (i.e. no JMS) then you +need `activemq-core-client.jar`, `activemq-commons.jar`, and `netty.jar` +on your client classpath. + +JMS Client +========== + +If you are using JMS on the client side, then you will also need to +include `activemq-jms-client.jar` and `jboss-jms-api.jar`. + +> **Note** +> +> `jboss-jms-api.jar` just contains Java EE API interface classes needed +> for the `javax.jms.*` classes. If you already have a jar with these +> interface classes on your classpath, you will not need it. http://git-wip-us.apache.org/repos/asf/activemq-6/blob/4245a6b4/docs/user-manual/en/client-classpath.xml ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/client-classpath.xml b/docs/user-manual/en/client-classpath.xml deleted file mode 100644 index 2baafbd..0000000 --- a/docs/user-manual/en/client-classpath.xml +++ /dev/null @@ -1,51 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- ============================================================================= --> -<!-- Licensed to the Apache Software Foundation (ASF) under one or more --> -<!-- contributor license agreements. See the NOTICE file distributed with --> -<!-- this work for additional information regarding copyright ownership. --> -<!-- The ASF licenses this file to You under the Apache License, Version 2.0 --> -<!-- (the "License"); you may not use this file except in compliance with --> -<!-- the License. You may obtain a copy of the License at --> -<!-- --> -<!-- http://www.apache.org/licenses/LICENSE-2.0 --> -<!-- --> -<!-- Unless required by applicable law or agreed to in writing, software --> -<!-- distributed under the License is distributed on an "AS IS" BASIS, --> -<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --> -<!-- See the License for the specific language governing permissions and --> -<!-- limitations under the License. --> -<!-- ============================================================================= --> - -<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ -<!ENTITY % BOOK_ENTITIES SYSTEM "ActiveMQ_User_Manual.ent"> -%BOOK_ENTITIES; -]> -<chapter id="client-classpath"> - <title>The Client Classpath</title> - <para>ActiveMQ requires several jars on the <emphasis>Client Classpath</emphasis> depending on - whether the client uses ActiveMQ Core API, JMS, and JNDI.</para> - <warning> - <para>All the jars mentioned here can be found in the <literal>lib</literal> directory of - the ActiveMQ distribution. Be sure you only use the jars from the correct version of the - release, you <emphasis>must not</emphasis> mix and match versions of jars from different - ActiveMQ versions. Mixing and matching different jar versions may cause subtle errors and - failures to occur.</para> - </warning> - <section> - <title>ActiveMQ Core Client</title> - <para>If you are using just a pure ActiveMQ Core client (i.e. no JMS) then you need <literal - >activemq-core-client.jar</literal>, <literal>activemq-commons.jar</literal>, and - <literal>netty.jar</literal> on your client classpath.</para> - </section> - <section> - <title>JMS Client</title> - <para>If you are using JMS on the client side, then you will also need to include <literal - >activemq-jms-client.jar</literal> and <literal>jboss-jms-api.jar</literal>.</para> - - <note> - <para><literal>jboss-jms-api.jar</literal> just contains Java EE API interface classes - needed for the <literal>javax.jms.*</literal> classes. If you already have a jar - with these interface classes on your classpath, you will not need it.</para> - </note> - </section> -</chapter> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/4245a6b4/docs/user-manual/en/client-reconnection.md ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/client-reconnection.md b/docs/user-manual/en/client-reconnection.md new file mode 100644 index 0000000..4ee441c --- /dev/null +++ b/docs/user-manual/en/client-reconnection.md @@ -0,0 +1,149 @@ +Client Reconnection and Session Reattachment +============================================ + +ActiveMQ clients can be configured to automatically reconnect or +re-attach to the server in the event that a failure is detected in the +connection between the client and the server. + +100% Transparent session re-attachment +====================================== + +If the failure was due to some transient failure such as a temporary +network failure, and the target server was not restarted, then the +sessions will still be existent on the server, assuming the client +hasn't been disconnected for more than connection-ttl ?. + +In this scenario, ActiveMQ will automatically re-attach the client +sessions to the server sessions when the connection reconnects. This is +done 100% transparently and the client can continue exactly as if +nothing had happened. + +The way this works is as follows: + +As ActiveMQ clients send commands to their servers they store each sent +command in an in-memory buffer. In the case that connection failure +occurs and the client subsequently reattaches to the same server, as +part of the reattachment protocol the server informs the client during +reattachment with the id of the last command it successfully received +from that client. + +If the client has sent more commands than were received before failover +it can replay any sent commands from its buffer so that the client and +server can reconcile their states. + +The size of this buffer is configured by the `ConfirmationWindowSize` +parameter, when the server has received `ConfirmationWindowSize` bytes +of commands and processed them it will send back a command confirmation +to the client, and the client can then free up space in the buffer. + +If you are using JMS and you're using the JMS service on the server to +load your JMS connection factory instances into JNDI then this parameter +can be configured in `activemq-jms.xml` using the element +`confirmation-window-size` a. If you're using JMS but not using JNDI +then you can set these values directly on the +`ActiveMQConnectionFactory` instance using the appropriate setter +method. + +If you're using the core API you can set these values directly on the +`ServerLocator` instance using the appropriate setter method. + +The window is specified in bytes. + +Setting this parameter to `-1` disables any buffering and prevents any +re-attachment from occurring, forcing reconnect instead. The default +value for this parameter is `-1`. (Which means by default no auto +re-attachment will occur) + +Session reconnection +==================== + +Alternatively, the server might have actually been restarted after +crashing or being stopped. In this case any sessions will no longer be +existent on the server and it won't be possible to 100% transparently +re-attach to them. + +In this case, ActiveMQ will automatically reconnect the connection and +*recreate* any sessions and consumers on the server corresponding to the +sessions and consumers on the client. This process is exactly the same +as what happens during failover onto a backup server. + +Client reconnection is also used internally by components such as core +bridges to allow them to reconnect to their target servers. + +Please see the section on failover ? to get a full understanding of how +transacted and non-transacted sessions are reconnected during +failover/reconnect and what you need to do to maintain *once and only +once*delivery guarantees. + +Configuring reconnection/reattachment attributes +================================================ + +Client reconnection is configured using the following parameters: + +- `retry-interval`. This optional parameter determines the period in + milliseconds between subsequent reconnection attempts, if the + connection to the target server has failed. The default value is + `2000` milliseconds. + +- `retry-interval-multiplier`. This optional parameter determines + determines a multiplier to apply to the time since the last retry to + compute the time to the next retry. + + This allows you to implement an *exponential backoff* between retry + attempts. + + Let's take an example: + + If we set `retry-interval` to `1000` ms and we set + `retry-interval-multiplier` to `2.0`, then, if the first reconnect + attempt fails, we will wait `1000` ms then `2000` ms then `4000` ms + between subsequent reconnection attempts. + + The default value is `1.0` meaning each reconnect attempt is spaced + at equal intervals. + +- `max-retry-interval`. This optional parameter determines the maximum + retry interval that will be used. When setting + `retry-interval-multiplier` it would otherwise be possible that + subsequent retries exponentially increase to ridiculously large + values. By setting this parameter you can set an upper limit on that + value. The default value is `2000` milliseconds. + +- `reconnect-attempts`. This optional parameter determines the total + number of reconnect attempts to make before giving up and shutting + down. A value of `-1` signifies an unlimited number of attempts. The + default value is `0`. + +If you're using JMS and you're using JNDI on the client to look up your +JMS connection factory instances then you can specify these parameters +in the JNDI context environment in, e.g. `jndi.properties`: + + java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory + java.naming.provider.url = tcp://localhost:5445 + connection.ConnectionFactory.retryInterval=1000 + connection.ConnectionFactory.retryIntervalMultiplier=1.5 + connection.ConnectionFactory.maxRetryInterval=60000 + connection.ConnectionFactory.reconnectAttempts=1000 + +If you're using JMS, but instantiating your JMS connection factory +directly, you can specify the parameters using the appropriate setter +methods on the `ActiveMQConnectionFactory` immediately after creating +it. + +If you're using the core API and instantiating the `ServerLocator` +instance directly you can also specify the parameters using the +appropriate setter methods on the `ServerLocator` immediately after +creating it. + +If your client does manage to reconnect but the session is no longer +available on the server, for instance if the server has been restarted +or it has timed out, then the client won't be able to re-attach, and any +`ExceptionListener` or `FailureListener` instances registered on the +connection or session will be called. + +ExceptionListeners and SessionFailureListeners +============================================== + +Please note, that when a client reconnects or re-attaches, any +registered JMS `ExceptionListener` or core API `SessionFailureListener` +will be called. http://git-wip-us.apache.org/repos/asf/activemq-6/blob/4245a6b4/docs/user-manual/en/client-reconnection.xml ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/client-reconnection.xml b/docs/user-manual/en/client-reconnection.xml deleted file mode 100644 index 96a4534..0000000 --- a/docs/user-manual/en/client-reconnection.xml +++ /dev/null @@ -1,147 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- ============================================================================= --> -<!-- Licensed to the Apache Software Foundation (ASF) under one or more --> -<!-- contributor license agreements. See the NOTICE file distributed with --> -<!-- this work for additional information regarding copyright ownership. --> -<!-- The ASF licenses this file to You under the Apache License, Version 2.0 --> -<!-- (the "License"); you may not use this file except in compliance with --> -<!-- the License. You may obtain a copy of the License at --> -<!-- --> -<!-- http://www.apache.org/licenses/LICENSE-2.0 --> -<!-- --> -<!-- Unless required by applicable law or agreed to in writing, software --> -<!-- distributed under the License is distributed on an "AS IS" BASIS, --> -<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --> -<!-- See the License for the specific language governing permissions and --> -<!-- limitations under the License. --> -<!-- ============================================================================= --> - -<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ -<!ENTITY % BOOK_ENTITIES SYSTEM "ActiveMQ_User_Manual.ent"> -%BOOK_ENTITIES; -]> -<chapter id="client-reconnection"> - <title>Client Reconnection and Session Reattachment</title> - <para>ActiveMQ clients can be configured to automatically reconnect or re-attach to the server in - the event that a failure is detected in the connection between the client and the server. </para> - <section> - <title>100% Transparent session re-attachment</title> - <para>If the failure was due to some transient failure such as a temporary network failure, - and the target server was not restarted, then the sessions will still be existent on the - server, assuming the client hasn't been disconnected for more than connection-ttl <xref - linkend="connection-ttl"/>.</para> - <para>In this scenario, ActiveMQ will automatically re-attach the client sessions to the - server sessions when the connection reconnects. This is done 100% transparently and the - client can continue exactly as if nothing had happened.</para> - <para>The way this works is as follows:</para> - <para>As ActiveMQ clients send commands to their servers they store each sent command in an - in-memory buffer. In the case that connection failure occurs and the client subsequently - reattaches to the same server, as part of the reattachment protocol the server informs - the client during reattachment with the id of the last command it successfully received - from that client.</para> - <para>If the client has sent more commands than were received before failover it can replay - any sent commands from its buffer so that the client and server can reconcile their - states.</para> - <para>The size of this buffer is configured by the <literal>ConfirmationWindowSize</literal> - parameter, when the server has received <literal>ConfirmationWindowSize</literal> bytes - of commands and processed them it will send back a command confirmation to the client, - and the client can then free up space in the buffer.</para> - <para>If you are using JMS and you're using the JMS service on the server to load your JMS - connection factory instances into JNDI then this parameter can be configured in <literal - >activemq-jms.xml</literal> using the element <literal - >confirmation-window-size</literal> a. If you're using JMS but not using JNDI then - you can set these values directly on the <literal>ActiveMQConnectionFactory</literal> - instance using the appropriate setter method.</para> - <para>If you're using the core API you can set these values directly on the <literal - >ServerLocator</literal> instance using the appropriate setter method.</para> - <para>The window is specified in bytes.</para> - <para>Setting this parameter to <literal>-1</literal> disables any buffering and prevents - any re-attachment from occurring, forcing reconnect instead. The default value for this - parameter is <literal>-1</literal>. (Which means by default no auto re-attachment will occur)</para> - </section> - <section> - <title>Session reconnection</title> - <para>Alternatively, the server might have actually been restarted after crashing or being - stopped. In this case any sessions will no longer be existent on the server and it won't - be possible to 100% transparently re-attach to them.</para> - <para>In this case, ActiveMQ will automatically reconnect the connection and <emphasis - role="italic">recreate</emphasis> any sessions and consumers on the server - corresponding to the sessions and consumers on the client. This process is exactly the - same as what happens during failover onto a backup server.</para> - <para>Client reconnection is also used internally by components such as core bridges to - allow them to reconnect to their target servers.</para> - <para>Please see the section on failover <xref linkend="ha.automatic.failover"/> to get a - full understanding of how transacted and non-transacted sessions are reconnected during - failover/reconnect and what you need to do to maintain <emphasis role="italic">once and - only once </emphasis>delivery guarantees.</para> - </section> - <section> - <title>Configuring reconnection/reattachment attributes</title> - <para>Client reconnection is configured using the following parameters:</para> - <itemizedlist> - <listitem> - <para><literal>retry-interval</literal>. This optional parameter determines the - period in milliseconds between subsequent reconnection attempts, if the - connection to the target server has failed. The default value is <literal - >2000</literal> milliseconds.</para> - </listitem> - <listitem> - <para><literal>retry-interval-multiplier</literal>. This optional parameter - determines determines a multiplier to apply to the time since the last retry to - compute the time to the next retry.</para> - <para>This allows you to implement an <emphasis>exponential backoff</emphasis> - between retry attempts.</para> - <para>Let's take an example:</para> - <para>If we set <literal>retry-interval</literal> to <literal>1000</literal> ms and - we set <literal>retry-interval-multiplier</literal> to <literal>2.0</literal>, - then, if the first reconnect attempt fails, we will wait <literal>1000</literal> - ms then <literal>2000</literal> ms then <literal>4000</literal> ms between - subsequent reconnection attempts.</para> - <para>The default value is <literal>1.0</literal> meaning each reconnect attempt is - spaced at equal intervals.</para> - </listitem> - <listitem> - <para><literal>max-retry-interval</literal>. This optional parameter determines the - maximum retry interval that will be used. When setting <literal - >retry-interval-multiplier</literal> it would otherwise be possible that - subsequent retries exponentially increase to ridiculously large values. By - setting this parameter you can set an upper limit on that value. The default - value is <literal>2000</literal> milliseconds.</para> - </listitem> - <listitem> - <para><literal>reconnect-attempts</literal>. This optional parameter determines the - total number of reconnect attempts to make before giving up and shutting down. A - value of <literal>-1</literal> signifies an unlimited number of attempts. The - default value is <literal>0</literal>.</para> - </listitem> - </itemizedlist> - <para>If you're using JMS and you're using JNDI on the client to look up your JMS - connection factory instances then you can specify these parameters - in the JNDI context environment in, e.g. <literal>jndi.properties</literal>:</para> - <programlisting> -java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory -java.naming.provider.url = tcp://localhost:5445 -connection.ConnectionFactory.retryInterval=1000 -connection.ConnectionFactory.retryIntervalMultiplier=1.5 -connection.ConnectionFactory.maxRetryInterval=60000 -connection.ConnectionFactory.reconnectAttempts=1000</programlisting> - <para>If you're using JMS, but instantiating your JMS connection factory directly, you can - specify the parameters using the appropriate setter methods on the <literal - >ActiveMQConnectionFactory</literal> immediately after creating it.</para> - <para>If you're using the core API and instantiating the <literal - >ServerLocator</literal> instance directly you can also specify the - parameters using the appropriate setter methods on the <literal - >ServerLocator</literal> immediately after creating it.</para> - <para>If your client does manage to reconnect but the session is no longer available on the - server, for instance if the server has been restarted or it has timed out, then the - client won't be able to re-attach, and any <literal>ExceptionListener</literal> or - <literal>FailureListener</literal> instances registered on the connection or session - will be called.</para> - </section> - <section id="client-reconnection.exceptionlistener"> - <title>ExceptionListeners and SessionFailureListeners</title> - <para>Please note, that when a client reconnects or re-attaches, any registered JMS <literal - >ExceptionListener</literal> or core API <literal>SessionFailureListener</literal> - will be called.</para> - </section> -</chapter> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/4245a6b4/docs/user-manual/en/clusters.md ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/clusters.md b/docs/user-manual/en/clusters.md new file mode 100644 index 0000000..6a1786c --- /dev/null +++ b/docs/user-manual/en/clusters.md @@ -0,0 +1,1059 @@ +Clusters +======== + +Clusters Overview +================= + +ActiveMQ clusters allow groups of ActiveMQ servers to be grouped +together in order to share message processing load. Each active node in +the cluster is an active ActiveMQ server which manages its own messages +and handles its own connections. + +> **Note** +> +> The *clustered* parameter is deprecated and no longer needed for +> setting up a cluster. If your configuration contains this parameter it +> will be ignored and a message with the ID `HQ221038` will be logged. + +The cluster is formed by each node declaring *cluster connections* to +other nodes in the core configuration file `activemq-configuration.xml`. +When a node forms a cluster connection to another node, internally it +creates a *core bridge* (as described in ?) connection between it and +the other node, this is done transparently behind the scenes - you don't +have to declare an explicit bridge for each node. These cluster +connections allow messages to flow between the nodes of the cluster to +balance load. + +Nodes can be connected together to form a cluster in many different +topologies, we will discuss a couple of the more common topologies later +in this chapter. + +We'll also discuss client side load balancing, where we can balance +client connections across the nodes of the cluster, and we'll consider +message redistribution where ActiveMQ will redistribute messages between +nodes to avoid starvation. + +Another important part of clustering is *server discovery* where servers +can broadcast their connection details so clients or other servers can +connect to them with the minimum of configuration. + +> **Warning** +> +> Once a cluster node has been configured it is common to simply copy +> that configuration to other nodes to produce a symmetric cluster. +> However, care must be taken when copying the ActiveMQ files. Do not +> copy the ActiveMQ *data* (i.e. the `bindings`, `journal`, and +> `large-messages` directories) from one node to another. When a node is +> started for the first time and initializes its journal files it also +> persists a special identifier to the `journal` directory. This id +> *must* be unique among nodes in the cluster or the cluster will not +> form properly. + +Server discovery +================ + +Server discovery is a mechanism by which servers can propagate their +connection details to: + +- Messaging clients. A messaging client wants to be able to connect to + the servers of the cluster without having specific knowledge of + which servers in the cluster are up at any one time. + +- Other servers. Servers in a cluster want to be able to create + cluster connections to each other without having prior knowledge of + all the other servers in the cluster. + +This information, let's call it the Cluster Topology, is actually sent +around normal ActiveMQ connections to clients and to other servers over +cluster connections. This being the case we need a way of establishing +the initial first connection. This can be done using dynamic discovery +techniques like +[UDP](http://en.wikipedia.org/wiki/User_Datagram_Protocol) and +[JGroups](http://www.jgroups.org/), or by providing a list of initial +connectors. + +Dynamic Discovery +----------------- + +Server discovery uses +[UDP](http://en.wikipedia.org/wiki/User_Datagram_Protocol) multicast or +[JGroups](http://www.jgroups.org/) to broadcast server connection +settings. + +### Broadcast Groups + +A broadcast group is the means by which a server broadcasts connectors +over the network. A connector defines a way in which a client (or other +server) can make connections to the server. For more information on what +a connector is, please see ?. + +The broadcast group takes a set of connector pairs, each connector pair +contains connection settings for a live and backup server (if one +exists) and broadcasts them on the network. Depending on which +broadcasting technique you configure the cluster, it uses either UDP or +JGroups to broadcast connector pairs information. + +Broadcast groups are defined in the server configuration file +`activemq-configuration.xml`. There can be many broadcast groups per +ActiveMQ server. All broadcast groups must be defined in a +`broadcast-groups` element. + +Let's take a look at an example broadcast group from +`activemq-configuration.xml` that defines a UDP broadcast group: + + <broadcast-groups> + <broadcast-group name="my-broadcast-group"> + <local-bind-address>172.16.9.3</local-bind-address> + <local-bind-port>5432</local-bind-port> + <group-address>231.7.7.7</group-address> + <group-port>9876</group-port> + <broadcast-period>2000</broadcast-period> + <connector-ref connector-name="netty-connector"/> + </broadcast-group> + </broadcast-groups> + +Some of the broadcast group parameters are optional and you'll normally +use the defaults, but we specify them all in the above example for +clarity. Let's discuss each one in turn: + +- `name` attribute. Each broadcast group in the server must have a + unique name. + +- `local-bind-address`. This is the local bind address that the + datagram socket is bound to. If you have multiple network interfaces + on your server, you would specify which one you wish to use for + broadcasts by setting this property. If this property is not + specified then the socket will be bound to the wildcard address, an + IP address chosen by the kernel. This is a UDP specific attribute. + +- `local-bind-port`. If you want to specify a local port to which the + datagram socket is bound you can specify it here. Normally you would + just use the default value of `-1` which signifies that an anonymous + port should be used. This parameter is always specified in + conjunction with `local-bind-address`. This is a UDP specific + attribute. + +- `group-address`. This is the multicast address to which the data + will be broadcast. It is a class D IP address in the range + `224.0.0.0` to `239.255.255.255`, inclusive. The address `224.0.0.0` + is reserved and is not available for use. This parameter is + mandatory. This is a UDP specific attribute. + +- `group-port`. This is the UDP port number used for broadcasting. + This parameter is mandatory. This is a UDP specific attribute. + +- `broadcast-period`. This is the period in milliseconds between + consecutive broadcasts. This parameter is optional, the default + value is `2000` milliseconds. + +- `connector-ref`. This specifies the connector and optional backup + connector that will be broadcasted (see ? for more information on + connectors). The connector to be broadcasted is specified by the + `connector-name` attribute. + +Here is another example broadcast group that defines a JGroups broadcast +group: + + <broadcast-groups> + <broadcast-group name="my-broadcast-group"> + <jgroups-file>test-jgroups-file_ping.xml</jgroups-file> + <jgroups-channel>activemq_broadcast_channel</jgroups-channel> + <broadcast-period>2000</broadcast-period> + <connector-ref connector-name="netty-connector"/> + </broadcast-group> + </broadcast-groups> + +To be able to use JGroups to broadcast, one must specify two attributes, +i.e. `jgroups-file` and `jgroups-channel`, as discussed in details as +following: + +- `jgroups-file` attribute. This is the name of JGroups configuration + file. It will be used to initialize JGroups channels. Make sure the + file is in the java resource path so that ActiveMQ can load it. + +- `jgroups-channel` attribute. The name that JGroups channels connect + to for broadcasting. + +> **Note** +> +> The JGroups attributes (`jgroups-file` and `jgroups-channel`) and UDP +> specific attributes described above are exclusive of each other. Only +> one set can be specified in a broadcast group configuration. Don't mix +> them! + +The following is an example of a JGroups file + + <config xmlns="urn:org:jgroups" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/JGroups-3.0.xsd"> + <TCP loopback="true" + recv_buf_size="20000000" + send_buf_size="640000" + discard_incompatible_packets="true" + max_bundle_size="64000" + max_bundle_timeout="30" + enable_bundling="true" + use_send_queues="false" + sock_conn_timeout="300" + + thread_pool.enabled="true" + thread_pool.min_threads="1" + thread_pool.max_threads="10" + thread_pool.keep_alive_time="5000" + thread_pool.queue_enabled="false" + thread_pool.queue_max_size="100" + thread_pool.rejection_policy="run" + + oob_thread_pool.enabled="true" + oob_thread_pool.min_threads="1" + oob_thread_pool.max_threads="8" + oob_thread_pool.keep_alive_time="5000" + oob_thread_pool.queue_enabled="false" + oob_thread_pool.queue_max_size="100" + oob_thread_pool.rejection_policy="run"/> + + <FILE_PING location="../file.ping.dir"/> + <MERGE2 max_interval="30000" + min_interval="10000"/> + <FD_SOCK/> + <FD timeout="10000" max_tries="5" /> + <VERIFY_SUSPECT timeout="1500" /> + <BARRIER /> + <pbcast.NAKACK + use_mcast_xmit="false" + retransmit_timeout="300,600,1200,2400,4800" + discard_delivered_msgs="true"/> + <UNICAST timeout="300,600,1200" /> + <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000" + max_bytes="400000"/> + <pbcast.GMS print_local_addr="true" join_timeout="3000" + view_bundling="true"/> + <FC max_credits="2000000" + min_threshold="0.10"/> + <FRAG2 frag_size="60000" /> + <pbcast.STATE_TRANSFER/> + <pbcast.FLUSH timeout="0"/> + </config> + +As it shows, the file content defines a jgroups protocol stacks. If you +want activemq to use this stacks for channel creation, you have to make +sure the value of `jgroups-file` in your broadcast-group/discovery-group +configuration to be the name of this jgroups configuration file. For +example if the above stacks configuration is stored in a file named +"jgroups-stacks.xml" then your `jgroups-file` should be like + + <jgroups-file>jgroups-stacks.xml</jgroups-file> + +### Discovery Groups + +While the broadcast group defines how connector information is +broadcasted from a server, a discovery group defines how connector +information is received from a broadcast endpoint (a UDP multicast +address or JGroup channel). + +A discovery group maintains a list of connector pairs - one for each +broadcast by a different server. As it receives broadcasts on the +broadcast endpoint from a particular server it updates its entry in the +list for that server. + +If it has not received a broadcast from a particular server for a length +of time it will remove that server's entry from its list. + +Discovery groups are used in two places in ActiveMQ: + +- By cluster connections so they know how to obtain an initial + connection to download the topology + +- By messaging clients so they know how to obtain an initial + connection to download the topology + +Although a discovery group will always accept broadcasts, its current +list of available live and backup servers is only ever used when an +initial connection is made, from then server discovery is done over the +normal ActiveMQ connections. + +> **Note** +> +> Each discovery group must be configured with broadcast endpoint (UDP +> or JGroups) that matches its broadcast group counterpart. For example, +> if broadcast is configured using UDP, the discovery group must also +> use UDP, and the same multicast address. + +### Defining Discovery Groups on the Server + +For cluster connections, discovery groups are defined in the server side +configuration file `activemq-configuration.xml`. All discovery groups +must be defined inside a `discovery-groups` element. There can be many +discovery groups defined by ActiveMQ server. Let's look at an example: + + <discovery-groups> + <discovery-group name="my-discovery-group"> + <local-bind-address>172.16.9.7</local-bind-address> + <group-address>231.7.7.7</group-address> + <group-port>9876</group-port> + <refresh-timeout>10000</refresh-timeout> + </discovery-group> + </discovery-groups> + +We'll consider each parameter of the discovery group: + +- `name` attribute. Each discovery group must have a unique name per + server. + +- `local-bind-address`. If you are running with multiple network + interfaces on the same machine, you may want to specify that the + discovery group listens only only a specific interface. To do this + you can specify the interface address with this parameter. This + parameter is optional. This is a UDP specific attribute. + +- `group-address`. This is the multicast IP address of the group to + listen on. It should match the `group-address` in the broadcast + group that you wish to listen from. This parameter is mandatory. + This is a UDP specific attribute. + +- `group-port`. This is the UDP port of the multicast group. It should + match the `group-port` in the broadcast group that you wish to + listen from. This parameter is mandatory. This is a UDP specific + attribute. + +- `refresh-timeout`. This is the period the discovery group waits + after receiving the last broadcast from a particular server before + removing that servers connector pair entry from its list. You would + normally set this to a value significantly higher than the + `broadcast-period` on the broadcast group otherwise servers might + intermittently disappear from the list even though they are still + broadcasting due to slight differences in timing. This parameter is + optional, the default value is `10000` milliseconds (10 seconds). + +Here is another example that defines a JGroups discovery group: + + <discovery-groups> + <discovery-group name="my-broadcast-group"> + <jgroups-file>test-jgroups-file_ping.xml</jgroups-file> + <jgroups-channel>activemq_broadcast_channel</jgroups-channel> + <refresh-timeout>10000</refresh-timeout> + </discovery-group> + </discovery-groups> + +To receive broadcast from JGroups channels, one must specify two +attributes, `jgroups-file` and `jgroups-channel`, as discussed in +details as following: + +- `jgroups-file` attribute. This is the name of JGroups configuration + file. It will be used to initialize JGroups channels. Make sure the + file is in the java resource path so that ActiveMQ can load it. + +- `jgroups-channel` attribute. The name that JGroups channels connect + to for receiving broadcasts. + +> **Note** +> +> The JGroups attributes (`jgroups-file` and `jgroups-channel`) and UDP +> specific attributes described above are exclusive of each other. Only +> one set can be specified in a discovery group configuration. Don't mix +> them! + +### Discovery Groups on the Client Side + +Let's discuss how to configure a ActiveMQ client to use discovery to +discover a list of servers to which it can connect. The way to do this +differs depending on whether you're using JMS or the core API. + +#### Configuring client discovery using JMS + +If you're using JMS and you're using JNDI on the client to look up your +JMS connection factory instances then you can specify these parameters +in the JNDI context environment. e.g. in `jndi.properties`. Simply +ensure the host:port combination matches the group-address and +group-port from the corresponding `broadcast-group` on the server. Let's +take a look at an example: + + java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory + java.naming.provider.url = udp://231.7.7.7:9876 + +The element `discovery-group-ref` specifies the name of a discovery +group defined in `activemq-configuration.xml`. + +When this connection factory is downloaded from JNDI by a client +application and JMS connections are created from it, those connections +will be load-balanced across the list of servers that the discovery +group maintains by listening on the multicast address specified in the +discovery group configuration. + +If you're using JMS, but you're not using JNDI to lookup a connection +factory - you're instantiating the JMS connection factory directly then +you can specify the discovery group parameters directly when creating +the JMS connection factory. Here's an example: + + final String groupAddress = "231.7.7.7"; + + final int groupPort = 9876; + + ConnectionFactory jmsConnectionFactory = + ActiveMQJMSClient.createConnectionFactory(new DiscoveryGroupConfiguration(groupAddress, groupPort, + new UDPBroadcastGroupConfiguration(groupAddress, groupPort, null, -1)), JMSFactoryType.CF); + + Connection jmsConnection1 = jmsConnectionFactory.createConnection(); + + Connection jmsConnection2 = jmsConnectionFactory.createConnection(); + +The `refresh-timeout` can be set directly on the +DiscoveryGroupConfiguration by using the setter method +`setDiscoveryRefreshTimeout()` if you want to change the default value. + +There is also a further parameter settable on the +DiscoveryGroupConfiguration using the setter method +`setDiscoveryInitialWaitTimeout()`. If the connection factory is used +immediately after creation then it may not have had enough time to +received broadcasts from all the nodes in the cluster. On first usage, +the connection factory will make sure it waits this long since creation +before creating the first connection. The default value for this +parameter is `10000` milliseconds. + +#### Configuring client discovery using Core + +If you're using the core API to directly instantiate +`ClientSessionFactory` instances, then you can specify the discovery +group parameters directly when creating the session factory. Here's an +example: + + final String groupAddress = "231.7.7.7"; + final int groupPort = 9876; + ServerLocator factory = ActiveMQClient.createServerLocatorWithHA(new DiscoveryGroupConfiguration(groupAddress, groupPort, + new UDPBroadcastGroupConfiguration(groupAddress, groupPort, null, -1)))); + ClientSessionFactory factory = locator.createSessionFactory(); + ClientSession session1 = factory.createSession(); + ClientSession session2 = factory.createSession(); + +The `refresh-timeout` can be set directly on the +DiscoveryGroupConfiguration by using the setter method +`setDiscoveryRefreshTimeout()` if you want to change the default value. + +There is also a further parameter settable on the +DiscoveryGroupConfiguration using the setter method +`setDiscoveryInitialWaitTimeout()`. If the session factory is used +immediately after creation then it may not have had enough time to +received broadcasts from all the nodes in the cluster. On first usage, +the session factory will make sure it waits this long since creation +before creating the first session. The default value for this parameter +is `10000` milliseconds. + +Discovery using static Connectors +--------------------------------- + +Sometimes it may be impossible to use UDP on the network you are using. +In this case its possible to configure a connection with an initial list +if possible servers. This could be just one server that you know will +always be available or a list of servers where at least one will be +available. + +This doesn't mean that you have to know where all your servers are going +to be hosted, you can configure these servers to use the reliable +servers to connect to. Once they are connected there connection details +will be propagated via the server it connects to + +### Configuring a Cluster Connection + +For cluster connections there is no extra configuration needed, you just +need to make sure that any connectors are defined in the usual manner, +(see ? for more information on connectors). These are then referenced by +the cluster connection configuration. + +### Configuring a Client Connection + +A static list of possible servers can also be used by a normal client. + +#### Configuring client discovery using JMS + +If you're using JMS and you're using JNDI on the client to look up your +JMS connection factory instances then you can specify these parameters +in the JNDI context environment in, e.g. `jndi.properties`: + + java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory + java.naming.provider.url=tcp://myhost:5445,myhost2:5445 + +The `java.naming.provider.url` contains a list of servers to use for the +connection factory. When this connection factory used client application +and JMS connections are created from it, those connections will be +load-balanced across the list of servers defined by the +`java.naming.provider.url`. + +If you're using JMS, but you're not using JNDI to lookup a connection +factory - you're instantiating the JMS connection factory directly then +you can specify the connector list directly when creating the JMS +connection factory. Here's an example: + + HashMap<String, Object> map = new HashMap<String, Object>(); + map.put("host", "myhost"); + map.put("port", "5445"); + TransportConfiguration server1 = new TransportConfiguration(NettyConnectorFactory.class.getName(), map); + HashMap<String, Object> map2 = new HashMap<String, Object>(); + map2.put("host", "myhost2"); + map2.put("port", "5446"); + TransportConfiguration server2 = new TransportConfiguration(NettyConnectorFactory.class.getName(), map2); + + ActiveMQConnectionFactory cf = ActiveMQJMSClient.createConnectionFactoryWithHA(JMSFactoryType.CF, server1, server2); + +#### Configuring client discovery using Core + +If you are using the core API then the same can be done as follows: + + HashMap<String, Object> map = new HashMap<String, Object>(); + map.put("host", "myhost"); + map.put("port", "5445"); + TransportConfiguration server1 = new TransportConfiguration(NettyConnectorFactory.class.getName(), map); + HashMap<String, Object> map2 = new HashMap<String, Object>(); + map2.put("host", "myhost2"); + map2.put("port", "5446"); + TransportConfiguration server2 = new TransportConfiguration(NettyConnectorFactory.class.getName(), map2); + + ServerLocator locator = ActiveMQClient.createServerLocatorWithHA(server1, server2); + ClientSessionFactory factory = locator.createSessionFactory(); + ClientSession session = factory.createSession(); + +Server-Side Message Load Balancing +================================== + +If cluster connections are defined between nodes of a cluster, then +ActiveMQ will load balance messages arriving at a particular node from a +client. + +Let's take a simple example of a cluster of four nodes A, B, C, and D +arranged in a *symmetric cluster* (described in ?). We have a queue +called `OrderQueue` deployed on each node of the cluster. + +We have client Ca connected to node A, sending orders to the server. We +have also have order processor clients Pa, Pb, Pc, and Pd connected to +each of the nodes A, B, C, D. If no cluster connection was defined on +node A, then as order messages arrive on node A they will all end up in +the `OrderQueue` on node A, so will only get consumed by the order +processor client attached to node A, Pa. + +If we define a cluster connection on node A, then as ordered messages +arrive on node A instead of all of them going into the local +`OrderQueue` instance, they are distributed in a round-robin fashion +between all the nodes of the cluster. The messages are forwarded from +the receiving node to other nodes of the cluster. This is all done on +the server side, the client maintains a single connection to node A. + +For example, messages arriving on node A might be distributed in the +following order between the nodes: B, D, C, A, B, D, C, A, B, D. The +exact order depends on the order the nodes started up, but the algorithm +used is round robin. + +ActiveMQ cluster connections can be configured to always blindly load +balance messages in a round robin fashion irrespective of whether there +are any matching consumers on other nodes, but they can be a bit +cleverer than that and also be configured to only distribute to other +nodes if they have matching consumers. We'll look at both these cases in +turn with some examples, but first we'll discuss configuring cluster +connections in general. + +Configuring Cluster Connections +------------------------------- + +Cluster connections group servers into clusters so that messages can be +load balanced between the nodes of the cluster. Let's take a look at a +typical cluster connection. Cluster connections are always defined in +`activemq-configuration.xml` inside a `cluster-connection` element. +There can be zero or more cluster connections defined per ActiveMQ +server. + + <cluster-connections> + <cluster-connection name="my-cluster"> + <address>jms</address> + <connector-ref>netty-connector</connector-ref> + <check-period>1000</check-period> + <connection-ttl>5000</connection-ttl> + <min-large-message-size>50000</min-large-message-size> + <call-timeout>5000</call-timeout> + <retry-interval>500</retry-interval> + <retry-interval-multiplier>1.0</retry-interval-multiplier> + <max-retry-interval>5000</max-retry-interval> + <initial-connect-attempts>-1</initial-connect-attempts> + <reconnect-attempts>-1</reconnect-attempts> + <use-duplicate-detection>true</use-duplicate-detection> + <forward-when-no-consumers>false</forward-when-no-consumers> + <max-hops>1</max-hops> + <confirmation-window-size>32000</confirmation-window-size> + <call-failover-timeout>30000</call-failover-timeout> + <notification-interval>1000</notification-interval> + <notification-attempts>2</notification-attempts> + <discovery-group-ref discovery-group-name="my-discovery-group"/> + </cluster-connection> + </cluster-connections> + +In the above cluster connection all parameters have been explicitly +specified. The following shows all the available configuration options + +- `address` Each cluster connection only applies to addresses that + match the specified address field. An address is matched on the + cluster connection when it begins with the string specified in this + field. The address field on a cluster connection also supports comma + separated lists and an exclude syntax '!'. To prevent an address + from being matched on this cluster connection, prepend a cluster + connection address string with '!'. + + In the case shown above the cluster connection will load balance + messages sent to addresses that start with `jms`. This cluster + connection, will, in effect apply to all JMS queues and topics since + they map to core queues that start with the substring "jms". + + The address can be any value and you can have many cluster + connections with different values of `address`, simultaneously + balancing messages for those addresses, potentially to different + clusters of servers. By having multiple cluster connections on + different addresses a single ActiveMQ Server can effectively take + part in multiple clusters simultaneously. + + Be careful not to have multiple cluster connections with overlapping + values of `address`, e.g. "europe" and "europe.news" since this + could result in the same messages being distributed between more + than one cluster connection, possibly resulting in duplicate + deliveries. + + Examples: + + - 'jms.eu' + matches all addresses starting with 'jms.eu' + - '!jms.eu' + matches all address except for those starting with 'jms.eu' + - 'jms.eu.uk,jms.eu.de' + matches all addresses starting with either 'jms.eu.uk' or + 'jms.eu.de' + - 'jms.eu,!jms.eu.uk' + matches all addresses starting with 'jms.eu' but not those + starting with 'jms.eu.uk' + + Notes: + + - Address exclusion will always takes precedence over address + inclusion. + - Address matching on cluster connections does not support + wild-card matching. + + This parameter is mandatory. + +- `connector-ref`. This is the connector which will be sent to other + nodes in the cluster so they have the correct cluster topology. + + This parameter is mandatory. + +- `check-period`. The period (in milliseconds) used to check if the + cluster connection has failed to receive pings from another server. + Default is 30000. + +- `connection-ttl`. This is how long a cluster connection should stay + alive if it stops receiving messages from a specific node in the + cluster. Default is 60000. + +- `min-large-message-size`. If the message size (in bytes) is larger + than this value then it will be split into multiple segments when + sent over the network to other cluster members. Default is 102400. + +- `call-timeout`. When a packet is sent via a cluster connection and + is a blocking call, i.e. for acknowledgements, this is how long it + will wait (in milliseconds) for the reply before throwing an + exception. Default is 30000. + +- `retry-interval`. We mentioned before that, internally, cluster + connections cause bridges to be created between the nodes of the + cluster. If the cluster connection is created and the target node + has not been started, or say, is being rebooted, then the cluster + connections from other nodes will retry connecting to the target + until it comes back up, in the same way as a bridge does. + + This parameter determines the interval in milliseconds between retry + attempts. It has the same meaning as the `retry-interval` on a + bridge (as described in ?). + + This parameter is optional and its default value is `500` + milliseconds. + +- `retry-interval-multiplier`. This is a multiplier used to increase + the `retry-interval` after each reconnect attempt, default is 1. + +- `max-retry-interval`. The maximum delay (in milliseconds) for + retries. Default is 2000. + +- `initial-connect-attempts`. The number of times the system will try + to connect a node in the cluster initially. If the max-retry is + achieved this node will be considered permanently down and the + system will not route messages to this node. Default is -1 (infinite + retries). + +- `reconnect-attempts`. The number of times the system will try to + reconnect to a node in the cluster. If the max-retry is achieved + this node will be considered permanently down and the system will + stop routing messages to this node. Default is -1 (infinite + retries). + +- `use-duplicate-detection`. Internally cluster connections use + bridges to link the nodes, and bridges can be configured to add a + duplicate id property in each message that is forwarded. If the + target node of the bridge crashes and then recovers, messages might + be resent from the source node. By enabling duplicate detection any + duplicate messages will be filtered out and ignored on receipt at + the target node. + + This parameter has the same meaning as `use-duplicate-detection` on + a bridge. For more information on duplicate detection, please see ?. + Default is true. + +- `forward-when-no-consumers`. This parameter determines whether + messages will be distributed round robin between other nodes of the + cluster *regardless* of whether or not there are matching or indeed + any consumers on other nodes. + + If this is set to `true` then each incoming message will be round + robin'd even though the same queues on the other nodes of the + cluster may have no consumers at all, or they may have consumers + that have non matching message filters (selectors). Note that + ActiveMQ will *not* forward messages to other nodes if there are no + *queues* of the same name on the other nodes, even if this parameter + is set to `true`. + + If this is set to `false` then ActiveMQ will only forward messages + to other nodes of the cluster if the address to which they are being + forwarded has queues which have consumers, and if those consumers + have message filters (selectors) at least one of those selectors + must match the message. + + Default is false. + +- `max-hops`. When a cluster connection decides the set of nodes to + which it might load balance a message, those nodes do not have to be + directly connected to it via a cluster connection. ActiveMQ can be + configured to also load balance messages to nodes which might be + connected to it only indirectly with other ActiveMQ servers as + intermediates in a chain. + + This allows ActiveMQ to be configured in more complex topologies and + still provide message load balancing. We'll discuss this more later + in this chapter. + + The default value for this parameter is `1`, which means messages + are only load balanced to other ActiveMQ serves which are directly + connected to this server. This parameter is optional. + +- `confirmation-window-size`. The size (in bytes) of the window used + for sending confirmations from the server connected to. So once the + server has received `confirmation-window-size` bytes it notifies its + client, default is 1048576. A value of -1 means no window. + +- `call-failover-timeout`. Similar to `call-timeout` but used when a + call is made during a failover attempt. Default is -1 (no timeout). + +- `notification-interval`. How often (in milliseconds) the cluster + connection should broadcast itself when attaching to the cluster. + Default is 1000. + +- `notification-attempts`. How many times the cluster connection + should broadcast itself when connecting to the cluster. Default is + 2. + +- `discovery-group-ref`. This parameter determines which discovery + group is used to obtain the list of other servers in the cluster + that this cluster connection will make connections to. + +Alternatively if you would like your cluster connections to use a static +list of servers for discovery then you can do it like this. + + <cluster-connection name="my-cluster"> + ... + <static-connectors> + <connector-ref>server0-connector</connector-ref> + <connector-ref>server1-connector</connector-ref> + </static-connectors> + </cluster-connection> + +Here we have defined 2 servers that we know for sure will that at least +one will be available. There may be many more servers in the cluster but +these will; be discovered via one of these connectors once an initial +connection has been made. + +Cluster User Credentials +------------------------ + +When creating connections between nodes of a cluster to form a cluster +connection, ActiveMQ uses a cluster user and cluster password which is +defined in `activemq-configuration.xml`: + + <cluster-user>ACTIVEMQ.CLUSTER.ADMIN.USER</cluster-user> + <cluster-password>CHANGE ME!!</cluster-password> + +> **Warning** +> +> It is imperative that these values are changed from their default, or +> remote clients will be able to make connections to the server using +> the default values. If they are not changed from the default, ActiveMQ +> will detect this and pester you with a warning on every start-up. + +Client-Side Load balancing +========================== + +With ActiveMQ client-side load balancing, subsequent sessions created +using a single session factory can be connected to different nodes of +the cluster. This allows sessions to spread smoothly across the nodes of +a cluster and not be "clumped" on any particular node. + +The load balancing policy to be used by the client factory is +configurable. ActiveMQ provides four out-of-the-box load balancing +policies, and you can also implement your own and use that. + +The out-of-the-box policies are + +- Round Robin. With this policy the first node is chosen randomly then + each subsequent node is chosen sequentially in the same order. + + For example nodes might be chosen in the order B, C, D, A, B, C, D, + A, B or D, A, B, C, D, A, B, C, D or C, D, A, B, C, D, A, B, C. + + Use + `org.apache.activemq.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy` + as the `<connection-load-balancing-policy-class-name>`. + +- Random. With this policy each node is chosen randomly. + + Use + `org.apache.activemq.api.core.client.loadbalance.RandomConnectionLoadBalancingPolicy` + as the `<connection-load-balancing-policy-class-name>`. + +- Random Sticky. With this policy the first node is chosen randomly + and then re-used for subsequent connections. + + Use + `org.apache.activemq.api.core.client.loadbalance.RandomStickyConnectionLoadBalancingPolicy` + as the `<connection-load-balancing-policy-class-name>`. + +- First Element. With this policy the "first" (i.e. 0th) node is + always returned. + + Use + `org.apache.activemq.api.core.client.loadbalance.FirstElementConnectionLoadBalancingPolicy` + as the `<connection-load-balancing-policy-class-name>`. + +You can also implement your own policy by implementing the interface +`org.apache.activemq.api.core.client.loadbalance.ConnectionLoadBalancingPolicy` + +Specifying which load balancing policy to use differs whether you are +using JMS or the core API. If you don't specify a policy then the +default will be used which is +`org.apache.activemq.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy`. + +If you're using JMS and you're using JNDI on the client to look up your +JMS connection factory instances then you can specify these parameters +in the JNDI context environment in, e.g. `jndi.properties`, to specify +the load balancing policy directly: + + java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory + java.naming.provider.url=tcp://localhost:5445 + connection.ConnectionFactory.loadBalancingPolicyClassName=org.apache.activemq.api.core.client.loadbalance.RandomConnectionLoadBalancingPolicy + +The above example would instantiate a JMS connection factory that uses +the random connection load balancing policy. + +If you're using JMS but you're instantiating your connection factory +directly on the client side then you can set the load balancing policy +using the setter on the `ActiveMQConnectionFactory` before using it: + + ConnectionFactory jmsConnectionFactory = ActiveMQJMSClient.createConnectionFactory(...); + jmsConnectionFactory.setLoadBalancingPolicyClassName("com.acme.MyLoadBalancingPolicy"); + +If you're using the core API, you can set the load balancing policy +directly on the `ServerLocator` instance you are using: + + ServerLocator locator = ActiveMQClient.createServerLocatorWithHA(server1, server2); + locator.setLoadBalancingPolicyClassName("com.acme.MyLoadBalancingPolicy"); + +The set of servers over which the factory load balances can be +determined in one of two ways: + +- Specifying servers explicitly + +- Using discovery. + +Specifying Members of a Cluster Explicitly +========================================== + +Sometimes you want to explicitly define a cluster more explicitly, that +is control which server connect to each other in the cluster. This is +typically used to form non symmetrical clusters such as chain cluster or +ring clusters. This can only be done using a static list of connectors +and is configured as follows: + + <cluster-connection name="my-cluster"> + <address>jms</address> + <connector-ref>netty-connector</connector-ref> + <retry-interval>500</retry-interval> + <use-duplicate-detection>true</use-duplicate-detection> + <forward-when-no-consumers>true</forward-when-no-consumers> + <max-hops>1</max-hops> + <static-connectors allow-direct-connections-only="true"> + <connector-ref>server1-connector</connector-ref> + </static-connectors> + </cluster-connection> + +In this example we have set the attribute +`allow-direct-connections-only` which means that the only server that +this server can create a cluster connection to is server1-connector. +This means you can explicitly create any cluster topology you want. + +Message Redistribution +====================== + +Another important part of clustering is message redistribution. Earlier +we learned how server side message load balancing round robins messages +across the cluster. If `forward-when-no-consumers` is false, then +messages won't be forwarded to nodes which don't have matching +consumers, this is great and ensures that messages don't arrive on a +queue which has no consumers to consume them, however there is a +situation it doesn't solve: What happens if the consumers on a queue +close after the messages have been sent to the node? If there are no +consumers on the queue the message won't get consumed and we have a +*starvation* situation. + +This is where message redistribution comes in. With message +redistribution ActiveMQ can be configured to automatically +*redistribute* messages from queues which have no consumers back to +other nodes in the cluster which do have matching consumers. + +Message redistribution can be configured to kick in immediately after +the last consumer on a queue is closed, or to wait a configurable delay +after the last consumer on a queue is closed before redistributing. By +default message redistribution is disabled. + +Message redistribution can be configured on a per address basis, by +specifying the redistribution delay in the address settings, for more +information on configuring address settings, please see ?. + +Here's an address settings snippet from `activemq-configuration.xml` +showing how message redistribution is enabled for a set of queues: + + <address-settings> + <address-setting match="jms.#"> + <redistribution-delay>0</redistribution-delay> + </address-setting> + </address-settings> + +The above `address-settings` block would set a `redistribution-delay` of +`0` for any queue which is bound to an address that starts with "jms.". +All JMS queues and topic subscriptions are bound to addresses that start +with "jms.", so the above would enable instant (no delay) redistribution +for all JMS queues and topic subscriptions. + +The attribute `match` can be an exact match or it can be a string that +conforms to the ActiveMQ wildcard syntax (described in ?). + +The element `redistribution-delay` defines the delay in milliseconds +after the last consumer is closed on a queue before redistributing +messages from that queue to other nodes of the cluster which do have +matching consumers. A delay of zero means the messages will be +immediately redistributed. A value of `-1` signifies that messages will +never be redistributed. The default value is `-1`. + +It often makes sense to introduce a delay before redistributing as it's +a common case that a consumer closes but another one quickly is created +on the same queue, in such a case you probably don't want to +redistribute immediately since the new consumer will arrive shortly. + +Cluster topologies +================== + +ActiveMQ clusters can be connected together in many different +topologies, let's consider the two most common ones here + +Symmetric cluster +----------------- + +A symmetric cluster is probably the most common cluster topology, and +you'll be familiar with if you've had experience of JBoss Application +Server clustering. + +With a symmetric cluster every node in the cluster is connected to every +other node in the cluster. In other words every node in the cluster is +no more than one hop away from every other node. + +To form a symmetric cluster every node in the cluster defines a cluster +connection with the attribute `max-hops` set to `1`. Typically the +cluster connection will use server discovery in order to know what other +servers in the cluster it should connect to, although it is possible to +explicitly define each target server too in the cluster connection if, +for example, UDP is not available on your network. + +With a symmetric cluster each node knows about all the queues that exist +on all the other nodes and what consumers they have. With this knowledge +it can determine how to load balance and redistribute messages around +the nodes. + +Don't forget [this warning](#copy-warning) when creating a symmetric +cluster. + +Chain cluster +------------- + +With a chain cluster, each node in the cluster is not connected to every +node in the cluster directly, instead the nodes form a chain with a node +on each end of the chain and all other nodes just connecting to the +previous and next nodes in the chain. + +An example of this would be a three node chain consisting of nodes A, B +and C. Node A is hosted in one network and has many producer clients +connected to it sending order messages. Due to corporate policy, the +order consumer clients need to be hosted in a different network, and +that network is only accessible via a third network. In this setup node +B acts as a mediator with no producers or consumers on it. Any messages +arriving on node A will be forwarded to node B, which will in turn +forward them to node C where they can get consumed. Node A does not need +to directly connect to C, but all the nodes can still act as a part of +the cluster. + +To set up a cluster in this way, node A would define a cluster +connection that connects to node B, and node B would define a cluster +connection that connects to node C. In this case we only want cluster +connections in one direction since we're only moving messages from node +A-\>B-\>C and never from C-\>B-\>A. + +For this topology we would set `max-hops` to `2`. With a value of `2` +the knowledge of what queues and consumers that exist on node C would be +propagated from node C to node B to node A. Node A would then know to +distribute messages to node B when they arrive, even though node B has +no consumers itself, it would know that a further hop away is node C +which does have consumers. + +Scaling Down +============ + +ActiveMQ supports scaling down a cluster with no message loss (even for +non-durable messages). This is especially useful in certain environments +(e.g. the cloud) where the size of a cluster may change relatively +frequently. When scaling up a cluster (i.e. adding nodes) there is no +risk of message loss, but when scaling down a cluster (i.e. removing +nodes) the messages on those nodes would be lost unless the broker sent +them to another node in the cluster. ActiveMQ can be configured to do +just that. + +The simplest way to enable this behavior is to set `scale-down` to +`true`. If the server is clustered and `scale-down` is `true` then when +the server is shutdown gracefully (i.e. stopped without crashing) it +will find another node in the cluster and send *all* of its messages +(both durable and non-durable) to that node. The messages are processed +in order and go to the *back* of the respective queues on the other node +(just as if the messages were sent from an external client for the first +time). + +If more control over where the messages go is required then specify +`scale-down-group-name`. Messages will only be sent to another node in +the cluster that uses the same `scale-down-group-name` as the server +being shutdown. + +> **Warning** +> +> If cluster nodes are grouped together with different +> `scale-down-group-name` values beware. If all the nodes in a single +> group are shut down then the messages from that node/group will be +> lost. + +If the server is using multiple `cluster-connection` then use +`scale-down-clustername` to identify the name of the +`cluster-connection` which should be used for scaling down.
