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节点,继续提供服务。
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被大量使用。
静态网络代理示意图
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集群。
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的文件夹。
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&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="openwire" uri="tcp://0.0.0.0:61617?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="openwire" uri="tcp://0.0.0.0:61618?maximumConnections=1000&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系统的功能验证、高可用及负载均衡功能验证。