天天看点

ActiveMQ高可用集群的搭建

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 模式。

ActiveMQ高可用集群的搭建

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 。

ActiveMQ高可用集群的搭建
ActiveMQ高可用集群的搭建
ActiveMQ高可用集群的搭建

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  集群的高可用)。