ActiveMQ高可用集群部署方案

1.概述

1.1简介

ActiveMQ是分布式系统中重要的组件,主要解决应用耦合、异步消息、流量削锋等问题,是大型分布式系统不可缺少的中间件。在生产环境中为了保证让ActiveMQ能够持续工作,我们还需要为消息中间件服务搭建集群环境,从而在保证消息中间件服务可靠性和处理性能。

1.2集群模式概述

集群模式主要是为了解决ActiveMQ系统架构中的两个关键问题:高可用和高性能。
针对上述两种需求,AActiveMQ主要有如下两种集群模式分别对应:

  • Master-slave模式
  • Broker-Cluster模式

1.2.1Master-slave模式

Master-Slave集群由至少3个节点组成,一个Master节点,其他为Slave节点。只有Master节点对外提供服务,Slave节点处于等待状态。当主节点宕机后,从节点会推举出一个节点出来成为新的Master节点,继续提供服务。
ActiveMQ高可用集群部署方案
Master-Slave模式的部署方式,主要分为三种:

  • Shared Filesystem Master-Slave方式,如KahaDB,应用灵活、高效且安全。
  • Shared Database Master-Slave方式,基于共享数据库,跟第一种类似,性能会受限于数据库。
  • Replicated LevelDB Store方式,基于zookeeper + leveldb。是生产环境常用的方案。

1.2.2Broker-Cluster模式

Broker-Cluster部署方式中,各个broker通过网络互相连接,自动分发调用端请求,从而实现集群的负载均衡。Broker-Cluster集群连接到网络代理的方式,主要分为静态网络代理、动态网络代理,不同的网络代理方式也对应了不同的集群部署方式:

  • static Broker-Cluster
  • Dynamic Broker-Cluster
    在实际应用场景中static Broker-Cluster被大量使用。

ActiveMQ高可用集群部署方案
静态网络代理示意图

1.3集群部署规划

1.3.1集群架构

Master-Slave集群的优点是可以解决多服务热备的高可用问题,但缺点是无法解决负载均衡和分布式的问题。Broker-Cluster集群的优点是可以解决负载均衡和分布式的问题,但不支持高可用。
因此,把Master-Slave和Broker-Cluster两者相结合,就可以得到一个完美的解决方案:即又可以做到集群负载均衡又可以做到任何一个broker如果发生宕机,也不会影响提供服务,节点消息也不会“丢失”。
在这里我们可以选择部署6个ActiveMQ实例,把6个ActiveMQ实例分成两组(Group)。Group1的三个节点通过Master-Slave模式组成brokerA,group2的3个节点通过Master-Slave模式组成brokerB,并使得brokerA与brokerB组成Broker-Cluster集群。
ActiveMQ高可用集群部署方案

1.3.2服务器规划

一般情况下,生产环境需要多个ActiveMQ配置在多台服务器中,但是由于本次环境搭建仅用于学习测试,且本地环境的机器规格受限,所以接下来我们将会在两个docker容器中进行模拟,每个容器以3组端口运行3个ActiveMQ实例。因为是在一台机器上做实验,即使运行两个docker容器,也需要在宿主机映射对应的端口。所以不同的ActiveMQ实例需要有不同的端口配置,具体分配如下:

节点 IP openwire端口 admin端口
mq1 172.18.0.112 61616 8161
mq2 172.18.0.112 61617 8162
mq3 172.18.0.112 61618 8163
mq4 172.18.0.116 61619 8164
mq5 172.18.0.116 61620 8165
mq6 172.18.0.116 61621 8166

2.环境准备

2.1容器及网络环境准备

1.拉取centos7镜像

docker pull centos:7

2.创建自定义docker网络
默认情况下启动的Docker容器,都是使用bridge网络,容器重启时,docker的IP就会发生改变,且不支持为容器指定固定IP。
因此我们需要基于bridge创建自定义网络。

docker network create --subnet=172.18.0.0/16 qqnetwork

3.创建activemq所需容器

docker run -i -t --name mqbrokerAA -p 61616:61616 -p 61617:61617 -p 61618:61618 -p 8161:8161 -p 8162:8162 -p 8163:8163 --privileged=true --net qqnetwork --ip 172.18.0.112 -d centos:7

docker run -i -t --name mqbrokerBB -p 61619:61619 -p 61620:61620 -p 61621:61621 -p 8164:8164 -p 8165:8165 -p 8166:8166 --privileged=true --net qqnetwork --ip 172.18.0.116 -d centos:7

2.2Java环境

ActiveMQ运行前需要确保已经安装配置jdk8的环境,这部分资料有很多,这里不再赘述。

3.集群部署

3.1搭建Master-Slave集群

3.1.1安装ActiveMQ

1.在/usr/local目录下创建mqcluster目录,然后在该目录中创建mq1,mq2,mq3的文件夹。
ActiveMQ高可用集群部署方案
2.将apache-activemq-5.15.3-bin.tar.gz压缩包的内容解压到这三个目录。

tar -zxvf apache-activemq-5.15.12-bin.tar.gz -C /usr/local/mqcluster/

3.分别单独运行3个ActiveMQ实例,保证单独运行正常。

3.1.2配置集群

3.1.2.1配置节点名

ActiveMQ Master-Slave集群的broker必须有统一的brokername,在这里需要修改ACTIVEMQ_HOME/conf/activemq.xml文件,将3个节点的brokerName统一为“brokerA”。

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="brokerA" dataDirectory="${activemq.data}">
3.1.2.2持久化配置

ActiveMQ的持久化主要有如下几种方案:

  • 基于日志文件存储,如KahaDB
  • JDBC消息存储,如使用mysql将消息持久化
  • LevelDB消息存储
    这里采用KahaDB的方式,原理就是让参与高可用的所有节点共用一个数据文件目录,通过文件锁的方式来决定谁是master谁是slave。在这里需要做的就是将3个节点的数据目录配置成相同的即可。

修改ACTIVEMQ_HOME/conf/activemq.xml文件,3个节点均修改成如下配置即可。

<persistenceAdapter>
     <kahaDB directory="/usr/local/mqcluster/mq1/data/kahadb"/>
</persistenceAdapter>
3.1.2.3TCP端口配置

实验环境暂时只用到tcp,所以只配置openwire,暂时将其它的端口配置注释掉。openwire默认为61616,同一个容器内端口不能重复,否则端口冲突,所以需要将mq1,mq2,mq3分别对应端口61616,61617,61618。
该配置也在ACTIVEMQ_HOME/conf/activemq.xml, 具体修改如下:

<transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
<transportConnector name="openwire" uri="tcp://0.0.0.0:61617?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
<transportConnector name="openwire" uri="tcp://0.0.0.0:61618?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
3.1.2.4Jetty端口配置

ActiveMQ使用jetty运行服务,与openwire同理,3个节点运行的端口必须不同。修改ACTIVEMQ_HOME/conf/jetty.xml,3个节点依次改为8161,8162,8163。

<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">
        <!-- the default port number for the web console -->
        <property name="host" value="0.0.0.0"/>
        <property name="port" value="8161"/>
</bean>
<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">
        <!-- the default port number for the web console -->
        <property name="host" value="0.0.0.0"/>
        <property name="port" value="8162"/>
</bean>
<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">
        <!-- the default port number for the web console -->
        <property name="host" value="0.0.0.0"/>
        <property name="port" value="8163"/>
</bean>

3.1.3启动集群

至此,ActiveMQ高可用集群已经配置好了,然后分别启动mq1,mq2,mq3实例。

/usr/local/mqcluster/mq1/bin/activemq start
/usr/local/mqcluster/mq2/bin/activemq start
/usr/local/mqcluster/mq3/bin/activemq start

如果配置正常,在后启动的两个节点的启动日志中会输出如下日志,表示已经有master锁定,自己将以slave角色运行。

注意:只有master节点接受请求,slave不接受请求,也无法使用管理界面。

3.2搭建Broker-Cluster集群

3.2.1搭建第二组Master-Slave集群

上面我们已经搭建好了一个Master-Slave集群,但仅仅是master-slave的话只能保证高可用,却无法做到负载均衡,如果mq因负载过大挂掉, master-slave也无法解决这种问题,所以就必须配置Broker-Cluster模式实现ActiveMQ集群的负载均衡。
此时,可以按照上述方式及前期的集群规划依次安装配置mq4/mq5/mq6,即可完成另一个Master-Slave集群。

3.2.2配置Broker-Cluster集群

Broker-Cluster部署方式中,“静态方式”在实际应用场景中被大量使用,因此我们这里采用静态uri方式,具体操作如下所示。
1.在group1中所有的节点修改ACTIVEMQ_HOME/conf/activemq.xml文件,添加如下配置链接group2(在persistenceAdapter标签前配置):

<networkConnectors>
    <networkConnector name="brokerB" uri="static:(tcp://172.18.0.116:61619,tcp://172.18.0.116:61620,tcp://172.18.0.116:61621)" duplex="true" />
</networkConnectors>

需要注意,broker-cluster模式duplex默认为false,这种情况下broker-cluster可以实现消息分发,但消息只存在一个broker上。与此同时,也就意味着,一旦broker宕机,则可能会出现消息丢失。
这里我们配置duplex="true",当这个节点使用Network Bridge连接到其它目标节点后,将强制目标也建立Network Bridge进行反向连接。其目的在于让消息既能发送到目标节点,又可以通过目标节点接受消息。它相当于下面几行的效果:

<!-- 在group1中 -->  
<networkConnector name="group1-broker1" uri="static:(tcp://172.18.0.116:61619)" duplex="false" />  
<!-- 在group1中 -->  
<networkConnector name="group1-broker2" uri="static:(tcp://172.18.0.116:61620)" duplex="false" />  
<!-- 在group1中 -->  
<networkConnector name="group1-broker3" uri="static:(tcp://172.18.0.116:61621)" duplex="false" /> 
 
 
<!-- 在group2中 -->  
<networkConnector name="group2-broker1" uri="static:(tcp://172.18.0.112:61616)" duplex="false" />  
<!-- 在group2中 -->  
<networkConnector name="group2-broker2" uri="static:(tcp://172.18.0.112:61617)" duplex="false" />  
<!-- 在group2中 -->  
<networkConnector name="group2-broker3" uri="static:(tcp://172.18.0.112:61618)" duplex="false" />

2.上一步配置duplex="true"后,group2中所有的节点则不需要再修改ACTIVEMQ_HOME/conf/activemq.xml文件,也不需要再链接group1。

到这里,我们就已经完成了ActiveMQ高可用+负载均衡的集群搭建。在下一篇文章我们将结合Java工程,完成对本次搭建的ActiveMQ系统的功能验证、高可用及负载均衡功能验证。

上一篇:同地域跨可用区容灾实践


下一篇:云服务器 ECS 镜像迁移:应用迁云之镜像迁移(1)概述