1 ActiveMQ集群的由来
1 基于zookeeper以及leveldb实现高可用ActiveMQ集群
1.2 搭建ActiveMQ步骤
1.2.1 准备环境
1.2.3 配置持久化适配器
1.2.4 修改消息服务端口
1.2.5 启动3个ActiveMQ集群节点
1.2.6 集群的节点状态分析
1.1.1 集群测试
单点的ActiveMQ作为企业应用无法满足业务的需求,因为单点的ActiveMQ存在单点故障问题,当该节点宕机以后,就会直接影响我们业务的正常运转,所以我们需要搭建高可用的ActiveMQ集群来支撑我们的业务系统
2 ActiveMQ集群的主要部署方式
2.1 默认的单机部署(kahadb)
activeMQ的默认存储的单机方式,以本地kahadb文件的方式存储,所以性能指标完全依赖本地磁盘IO,不能提供高可用。
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
2.2 基于共享数据库的主从(Shared JDBC Master/Slave)
可以基于
postgres
、
mysql
、
oracle
等常用数据库。每个节点启动都会争抢数据库锁,从而保证
master
的唯一性,其他节点作为备份,一直等待数据库锁的释放。因为所有消息读写,其实都是数据库操作,
activeMQ
节点本身压力很小,性能完全取决于数据库性能。优点:实现高可用和数据安全
,
简单灵活,
2
台节点就可以实现高可用
.
缺点:稳定性依赖数据库
,
性能依赖数据库
.
<beanid="mysql-ds"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<property name="driverClassName"value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/amq?relaxAutoCommit=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="maxActive" value="20"/>
<property name="poolPreparedStatements"value="true"/>
<property name="driverClassName"value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/amq?relaxAutoCommit=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="maxActive" value="20"/>
<property name="poolPreparedStatements"value="true"/>
</bean>
<persistenceAdapter>
<jdbcPersistenceAdapter dataDirectory="${activemq.data}"dataSource="#mysql-ds"
createTablesOnStartup="false"/>
<jdbcPersistenceAdapter dataDirectory="${activemq.data}"dataSource="#mysql-ds"
createTablesOnStartup="false"/>
</persistenceAdapter>
2.3 基于zookeeper以及可复制的 LevelDB实现
5.9.0
新推出的主从实现,基于
zookeeper
来选举出一个
master
,其他节点自动作为
slave
实时同步消息。因为有实时同步数据的
slave
的存在,
master
不用担心数据丢失,所以
leveldb
会优先采用内存存储消息,异步同步到磁盘。所以该方式的
activeMQ
读写性能都最好
,特别是写性能能够媲美非持久化消息。优点:实现高可用和数据安全性能较好
.
缺点:因为选举机制要超过半数,所以最少需要
3
台节点
,才能实现高可用。
LevelDB 是 Google 开发的一套用于持久化数据的高性能类库。 LevelDB 并不是一种服务 , 用户需要自行实现 Server 。 是单进程的服务,能够处理十亿级别规模 Key-Value 型数据,占用内存小。
LevelDB 是 Google 开发的一套用于持久化数据的高性能类库。 LevelDB 并不是一种服务 , 用户需要自行实现 Server 。 是单进程的服务,能够处理十亿级别规模 Key-Value 型数据,占用内存小。
<persistenceAdapter>
<replicatedLevelDB
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:62621"
zkAddress="localhost:2181,localhost:2182,localhost:2183"
hostname="localhost"
zkPath="/activemq/leveldb-stores"
/>
<replicatedLevelDB
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:62621"
zkAddress="localhost:2181,localhost:2182,localhost:2183"
hostname="localhost"
zkPath="/activemq/leveldb-stores"
/>
</persistenceAdapter>
了解完毕
ActiveMQ
集群的三种部署方式以后
,
我们本教程将采用第三种方式来建
ActiveMQ
集群
,
因为第三种的读写性能都最好的
.
3 ActiveMQ高可用原理
使用
ZooKeeper
(集群)注册所有的
ActiveMQ Broker
。只有其中的一个
Broker
可以提供服务,被视为
Master
,其他的
Broker
处于待机状态,被视为
Slave
。如果
Master
因故障而不能提供服务,
Zookeeper
会从
Slave
中选举出一个
Broker
充当
Master
。
Slave
连接
Master
并同步他们的存储状态,
Slave
不接受客户端连接。所有的存储操作都将被复制到
连接至
Master
的
Slaves
。如果
Master
宕了,得到了最新更新的
Slave
会成为
Master
。故障节点在恢复后会重新加入到集群中并连接
Master
进入
Slave
模式。
![](https://i-blog.csdnimg.cn/blog_migrate/8400b56c7285aafbe39dd2559492ea2c.jpeg)
了解完毕
ActiveMQ
集群的三种部署方式以后
,
我们本教程将采用第三种方式来建
ActiveMQ
集群
,
因为第三种的读写性能都最好的
.
1.1 ActiveMQ集群部署规划
环境:
CentOS 6.6 x64
、
JDK7
版本: ActiveMQ 5.11.1
版本: ActiveMQ 5.11.1
zookeeper
集群说明
:
192.168.221.141:2181 , 192.168.221.141:2182, 192.168.221.141:2183
集群节点规划说明
:
主机
|
集群间通信端口
|
消息端口
|
管控台端口
|
其他端口
|
安装目录
|
192.168.221.136
|
62621
|
11616
|
8161
|
以
1
开始即可
|
/usr/local/src/activemq-cluster
|
192.168.221.136
|
62622
|
21616
|
8162
|
以
2
开始即可
| |
192.168.221.136
|
62623
|
31616
|
8163
|
以
3
开始即可
|
Ø 在/usr/local/src/在创建activemq-cluster目录: mkdir –p /usr/local/src/activemq-cluster
Ø 上传activemq安装包到linux服务器下
Ø 解压activemq的安装包: tar –zxvf –C /usr/local/src/activemq-cluster
Ø 重命名: mv apache-activemq-5.12.0/ activemq-cluster-node01
Ø 以1节点为基础复制两个节点出来
² cp –r activemq-cluster-node01 activemq-cluster-node02
² cp –r activemq-cluster-node01 activemq-cluster-node03
1.2.2 修改管理控制台端口可在 conf/jetty.xml 中修改
node01
管控台端口
<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">
<property name="host" value="0.0.0.0"/>
<property name="port" value="8161"/>
</bean>
|
node02
管控台端口
<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">
<property name="host" value="0.0.0.0"/>
<property name="port" value="8162"/>
</bean>
|
node03
管控台端口
<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">
<property name="host" value="0.0.0.0"/>
<property name="port" value="8163"/>
</bean>
|
在 3 个 ActiveMQ 节点中配置
conf/activemq.xml 中的持久化适配器。修改其中 bind、zkAddress、hostname 和 zkPath.
注意
:
每个
ActiveMQ
的
BrokerName
必须相同,否则不能加入集群。
node01-
持久化适配器
:
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="activemq-cluster" dataDirectory="${activemq.data}">
<persistenceAdapter>
<replicatedLevelDB
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://192.168.221.136:62621"
zkAddress="192.168.80.129:2182,192.168.80.129:2183,192.168.80.129:2184"
hostname="192.168.80.129"
zkPath="/activemq/leveldb-stores"
/>
</persistenceAdapter>
</broker>
|
node02-
持久化适配器
:
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="activemq-cluster" dataDirectory="${activemq.data}">
<persistenceAdapter>
<replicatedLevelDB
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://192.168.221.136:62622"
zkAddress="192.168.221.145:2181,192.168.221.145:2182,192.168.221.145:2183"
hostname="192.168.221.136"
zkPath="/activemq/leveldb-stores"
/>
</persistenceAdapter>
</broker>
|
node03-
持久化适配器
:
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="activemq-cluster" dataDirectory="${activemq.data}">
<persistenceAdapter>
<replicatedLevelDB
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://192.168.221.136:62623"
zkAddress="192.168.221.145:2181,192.168.221.145:2182,192.168.221.145:2183"
hostname="192.168.221.136"
zkPath="/activemq/leveldb-stores"
/>
</persistenceAdapter>
</broker>
|
node-01
消息服务端口:
<transportConnectors>
<transportConnector name="openwire" uri="tcp://0.0.0.0:11616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="amqp" uri="amqp://0.0.0.0:1672?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="stomp" uri="stomp://0.0.0.0:11613?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="ws" uri="ws://0.0.0.0:11614?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
|
node-02
消息服务端口:
<transportConnectors>
<transportConnector name="openwire" uri="tcp://0.0.0.0:21616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="amqp" uri="amqp://0.0.0.0:2672?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="stomp" uri="stomp://0.0.0.0:21613?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="mqtt" uri="mqtt://0.0.0.0:2883?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="ws" uri="ws://0.0.0.0:21614?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
|
node-03
消息服务端口:
<transportConnectors>
<transportConnector name="openwire" uri="tcp://0.0.0.0:31616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="amqp" uri="amqp://0.0.0.0:3672?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="stomp" uri="stomp://0.0.0.0:31613?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="mqtt" uri="mqtt://0.0.0.0:3883?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="ws" uri="ws://0.0.0.0:31614?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
|
/usr/local/src/activemq-cluster/apache-activemq-01/bin/activemq start
/usr/local/src/activemq-cluster/apache-activemq-02/bin/activemq start
/usr/local/src/activemq-cluster/apache-activemq-03/bin/activemq start
监听日志
tail -f /usr/local/src/activemq-cluster/apache-activemq-01/data/activemq.log
tail -f /usr/local/src/activemq-cluster/apache-activemq-02/data/activemq.log
tail -f /usr/local/src/activemq-cluster/apache-activemq-03/data/activemq.log
|
使用集群启动后对
ZooKeeper
数据的抓图,可以看到
ActiveMQ
的有
3
个节点,分别是
00000000019
,
000000000020
,
00000000021
。以下第一张图展现了
00000000019
的值,可以看到
elected
的值是不为空,说明这个节点是
Master
,其他两个节点是
Slave
。
![](https://i-blog.csdnimg.cn/blog_migrate/71ffc93d68f70fda8712e14bd1da0693.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/4b578a1c5c894ec4af357d757c1857a6.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/7d2e78baff35db385de330459d4ce48a.jpeg)
ActiveMQ
的客户端只能访问
MasterBroker,
其他处于
Slave
的
Broker
不能访问
.
所以客户端连接
Broker
应该使用
failover(
故障转移
)
协议
failover:(tcp://192.168.221.136:11616,tcp://192.168.221.136:21616,tcp:// 192.168.221.136:31616)?randomize=false
1.1.2 客户端连接url配置优化
updateURIsURL
,通过
URL
(或者本地路径)获取重连的
url
,这样做具有良好的扩展性,因为客户端每次连接都是从
URL
(或文件)中加载一次,所以可以随时从文件中更新
url
列表,做到动态添加
MQ
的备点。
failover:()?randomize=false&updateURIsURL=file:/home/wusc/activemq/urllist.txt,urllist.txt
中的地址通过英文逗号分隔,示例:
tcp://192.168.221.136:11616,tcp://192.168.221.136:21616,tcp:// 192.168.221.136:31616
1.1.3 集群测试结果说明
当一个
ActiveMQ
节点挂掉
,
或者一个
ZooKeeper
节点挂掉
,ActiveMQ
服务依然正常运转
.
如果仅剩一个
ActiveMQ
节点
,
因为不能选举
Master,ActiveMQ
不能正常运转
;
同样的
,
如果
ZooKeeper
仅剩一个节点活动
.
不管
ActiveMQ
各节点是否存活
,ActiveMQ
也不能正常提供服务。
(ActiveMQ
集群的高可用,依赖于
ZooKeeper
集群的高可用)。