人生是海洋,希望是舵手的罗盘,使人们在暴风雨中不致迷失方向。 —— 狄德罗
1. 前言
ActiveMQ Master/Slave集群可以提高ActiveMQ的高可用性,一旦一个Broker出现故障不可用时,另一个Broker可以迅速代替其成为Master角色。Master/Slave集群不支持负载均衡,仅能解决单点故障。
ActiveMQ 提供了三种集群配置方式:
- 基于共享文件系统(KahaDB)
- 基于JDBC
- 基于可复制的Level DB + Zookeeper
2. 基于共享文件系统(KahaDB)
我们在同一台机器上部署两个Broker来模拟集群,若是分别在两台机器上部署,还需要两台机器能共享文件系统。
2.1 修改持久化适配器(persistenceAdapter)
在activemq1和activemq2的activemq.xml中,找到persistenceAdapter。修改kahaDB的共享文件目录。
<persistenceAdapter>
<kahaDB directory="F:/develop/tool/activemq-cluster/kahadb"/>
</persistenceAdapter>
2.2 修改端口号
ActiveMQ默认端口是61616,因两Broker的端口不允许重复,因此需要将activemq2的端口更换为另一个端口号。
<transportConnectors>
<!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
<transportConnector name="openwire" uri="tcp://0.0.0.0:61617?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
2.3 启动Broker
分别启动两个Broker服务器,第一个Broker启动完成后,再接着启动第二个Broker,控制台中的日志如下:
.......
Using Persistence Adapter: KahaDBPersistenceAdapter[F:\develop\tool\activemq-cluster\kahadb]
jvm 1 | INFO | Database F:\develop\tool\activemq-cluster\kahadb\lock is locked by another server. This broker is now in slave mode waiting a lock to be acquired
从上面的日志可以看出,因F:\develop\tool\activemq-cluster\kahadb\lock is locked,导致第二个Broker是作为Slave启动的,第一个Broker那就是Master服务器了。
接着将Master Broker关停后,Slave Broker则迅速代替成为Master。再次启动activemq1,则是以Slave的身份启动的。
集群启动后,只有率先启动的节点(Master)一直锁定这lock文件,其它节点(Slave)由于不能访问该文件而等待启动。一旦Master节点挂掉,lock文件锁被释放;其它Slave节点中率先锁定lock文件的,成为Master节点。
3. 基于JDBC(以MYSQL为例)
3.1 配置数据库连接池
分别在两个broker的activemq.xml中增加配置数据库连接池,可添加在</broker>标签的后面。
<!--配置数据库连接池-->
<bean name="mysql-ds" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/db_activemq?useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="123456"/>
</bean>
需要把mysql的驱动jar包和Druid的jar包放在各节点的lib目录下。
3.2 修改持久化适配器(persistenceAdapter)
修改persistenceAdapter配置项,注释掉Kahadb的配置,配置上JDBC方式的persistenceAdapter。
<persistenceAdapter>
<!--<kahaDB directory="F:/develop/tool/activemq-cluster/kahadb"/>-->
<!--createTablesOnStartup="false" 在启动前不要配置,等集群启动过了,再配置。createTablesOnStartup是启动时创建表,只创建一次就够了-->
<jdbcPersistenceAdapter dataDirectory="${activemq.data}" dataSource="#mysql-ds" createTablesOnStartup="false" useDatabaseLock="true"/>
</persistenceAdapter>
依次启动activemq1和activemq2,发现只有activemq1启动成功,activemq2处于等待获取锁的状态。当抢到锁的broker宕机了,activemq2会抢到锁,成为Master。
启动Broker后,会创建activemq_acks、activemq_lock和activemq_msgs三张表。
(1)activemq_acks:用于存储订阅关系。如果是持久化Topic,订阅者和服务器的订阅关系在这个表保存。
(2)activemq_lock:在集群环境中才有用,只有一个Broker可以获得消息,称为Master Broker,其他的只能作为备份等待Master Broker不可用,才可能成为下一个Master Broker。这个表用于记录哪个Broker是当前的Master Broker。
(3)activemq_msgs:用于存储消息,Queue和Topic都存储在这个表中。
使用生产者产生消息,会存放在表activemq_msgs中:
启动消费者消费这些消息后:
4. 基于可复制LevelDB + Zookeeper
Leveldb是一个google实现的非常高效的kv数据库,是单进程的服务,能够处理十亿级别规模Key-Value型数据,占用内存小。
基于可复制LevelDB的集群方案,需要引入ZooKeeper。根据ZooKeeper的使用方式可以分为单节点的ZooKeeper和Zookeeper集群。这里我们只讲述ZooKeeper集群,单节点不是一个可靠的选择。
4.1 Zookeeper集群配置
ZooKeeper分部署在下面三个目录中。
F:\develop\tool\activemq-cluster\zookeeper1
F:\develop\tool\activemq-cluster\zookeeper2
F:\develop\tool\activemq-cluster\zookeeper3
4.1.1 配置zoo.cfg
把3个节点中config目录下的zoo_sample.cfg复制一份,改成zoo.cfg。
因为是在一台主机上部署,所以每个zoo.cfg中的clientPort不能重复;如果有三台主机,那么采用默认的clientPort就行,同理server.1、server.2、server.3可以写作<各自ip>:2888:3888。
其中zookeeper1中的配置如下:
#默认配置
tickTime=2000
initLimit=10
syncLimit=5
#需要修改的配置
dataDir=D:/MQ/apache-activemq/cluster/zkdata/z1/
clientPort=2181
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890
zookeeper2中的配置如下:
#默认配置
tickTime=2000
initLimit=10
syncLimit=5
#需要修改的配置
dataDir=D:/MQ/apache-activemq/cluster/zkdata/z2/
clientPort=2182
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890
zookeeper3中的配置如下:
#默认配置
tickTime=2000
initLimit=10
syncLimit=5
#需要修改的配置
dataDir=D:/MQ/apache-activemq/cluster/zkdata/z3/
clientPort=2183
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890
4.1.2 配置myid
4.1.2 myid
创建三个目录
F:\develop\tool\activemq-cluster\zkdata\z1
F:\develop\tool\activemq-cluster\zkdata\z2
F:\develop\tool\activemq-cluster\zkdata\z3
每个目录中都创建一个名为myid的文件(文本文件,删掉txt后缀),3个文件的内容分别写1、2、3。
F:\develop\tool\activemq-cluster\zkdata\z1\myid 1
F:\develop\tool\activemq-cluster\zkdata\z2\myid 2
F:\develop\tool\activemq-cluster\zkdata\z3\myid 3
4.2 ActiveMQ配置
在3个amq节点中配置activemq.xml中的持久化适配器。根据以下配置示例,修改其中bind、zkAddress和hostname。如果你是在三台主机上部署,那么bind项可以写成bind="tcp://0.0.0.0:0",默认采用61619端口。我们这里在一台主机上演示,因此需要保证bind端口不冲突。
activemq1的配置如下:
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="activemq" dataDirectory="${activemq.data}">
......
<persistenceAdapter>
<replicatedLevelDB
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:62616"
zkAddress="localhost:2181,localhost:2182,localhost:2183"
hostname="localhost"
zkPath="/activemq/leveldb-stores"
/>
</persistenceAdapter>
......
</broker>
activemq2的配置如下:
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="activemq" dataDirectory="${activemq.data}">
......
<persistenceAdapter>
<replicatedLevelDB
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:62617"
zkAddress="localhost:2181,localhost:2182,localhost:2183"
hostname="localhost"
zkPath="/activemq/leveldb-stores"
/>
</persistenceAdapter>
......
</broker>
activemq3的配置如下:
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="activemq" dataDirectory="${activemq.data}">
......
<persistenceAdapter>
<replicatedLevelDB
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:62618"
zkAddress="localhost:2181,localhost:2182,localhost:2183"
hostname="localhost"
zkPath="/activemq/leveldb-stores"
/>
</persistenceAdapter>
......
</broker>
注意无论是master节点还是salve节点,它们的brokerName属性都必须一致,
否则activeMQ集群就算连接到了zookeeper,也不会把他们当成一个Master/Salve组。
4.3 ActiveMQ配置
先依次启动ZooKeeper,再依次启动ActiveMQ。启动第1个Zookeeper时,控制台会报连接错误,因为其它的ZooKeeper节点还没启动。
第一个Broker启动后,会成为Master。
随后启动的Broker都会成为slave。
当Master Broker宕机后,剩余的slave会竞争成为Master。
4.3 注意点
对于replicas属性,官方给出的解释如下:
The number of nodes that will exist in the cluster. At least (replicas/2)+1 nodes must be online to avoid service outage.(default:3)
这里的“number of nodes”包括了Master节点和Salve节点的总和。换句话说,如果您的集群中一共有3个ActiveMQ节点,且只允许最多有一个节点出现故障。那么这里的值可以设置为2(当然设置为3也行,因为整型计算中 3 / 2 + 1 = 2)。但如果您将replicas属性设置为4,就代表不允许3个节点的任何一个节点出错,因为:(4 / 2) + 1 = 3,也就是说3个节点是本集群能够允许的最小节点数。
一旦zookeeper发现当前集群中可工作的ActiveMQ节点数小于所谓的“At least (replicas/2)+1 nodes”,在ActiveMQ Master节点的日志中就会给出提示:“Not enough cluster members connected to elect a master.”,然后整个集群都会停止工作,直到有新的节点连入,并达到所规定的“At least (replicas/2)+1 nodes”数量。
bind属性指明了当本节点成为一个Master节点后,通过哪一个通讯位置进行和其它Salve节点的消息复制操作。注意这里配置的监听地址和端口不能在transportConnectors标签中进行重复配置,否则节点在启动时会报错。
zkAddress属性指明了连接的zookeeper服务节点所在的位置。如果您有多个zookeeper服务节点,那么请依次配置这些zookeeper服务节点的位置,并以“,”进行分隔。