1 ActiveMQ集群的由来 单点的ActiveMQ作为企业应用无法满足业务的需求,因为单点的ActiveMQ存在单点故障问题,当该节点宕机以后,就会直接影响我们业务的正常运转,所以我们需要搭建高可用的ActiveMQ集群来支撑我们的业务系统 2 ActiveMQ集群的主要部署方式 2.1 默认的单机部署(kahadb) activeMQ的默认存储的单机方式,以本地kahadb文件的方式存储,所以性能指标完全依赖本地磁盘IO,不能提供高可用。 <persistenceAdapter>
<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"/> </bean> <persistenceAdapter>
<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 型数据,占用内存小。 <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"
/> </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://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnauIWb1hGducmbw5Cb2BXbwpWapNWa1pWZwhHaxQjNxcTMvwVOy8CXzADOxAjMvwVb1J3bm9CX05WZth2YhRHdh9CXhRXYk9CXt92YuEWbpVGa0lmLzJmYvw1LcpDc0RHaiojIsJye.jpg)
1 基于zookeeper以及leveldb实现高可用ActiveMQ集群 了解完毕 ActiveMQ 集群的三种部署方式以后 , 我们本教程将采用第三种方式来建 ActiveMQ 集群 , 因为第三种的读写性能都最好的 . 1.1 ActiveMQ集群部署规划 环境: CentOS 6.6 x64 、 JDK7
版本: 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 开始即可 |
1.2 搭建ActiveMQ步骤 1.2.1 准备环境 Ø 在/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> |
1.2.3 配置持久化适配器 在 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> |
1.2.4 修改消息服务端口 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> |
1.2.5 启动3个ActiveMQ集群节点
/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 |
1.2.6 集群的节点状态分析
使用集群启动后对 ZooKeeper 数据的抓图,可以看到 ActiveMQ 的有 3 个节点,分别是 00000000019 , 000000000020 , 00000000021 。以下第一张图展现了 00000000019 的值,可以看到 elected 的值是不为空,说明这个节点是 Master ,其他两个节点是 Slave 。
1.1.1 集群测试 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 集群的高可用)。