ActiveMQ基于LevelDB的Zookeeper高可用集群

来源:互联网 发布:网络约车平台架构图 编辑:程序博客网 时间:2024/05/19 16:47

这里写图片描述

是对ActiveMQ进行高可用的一种有效的解决方案,高可用的原理:使用ZooKeeper(集群)注册所有的ActiveMQ Broker。只有其中的一个Broker可以对外提供服务(也就是Master节点),其他的Broker处于待机状态,被视为Slave。如果Master因故障而不能提供服务,则利用ZooKeeper的内部选举机制会从Slave中选举出一个Broker充当Master节点,继续对外提供服务。

官网文档如下:

http://activemq.apache.org/replicated-leveldb-store.html

这里写图片描述

这里写图片描述

这里写图片描述

主机IP 消息端口 通信端口 节点目录/usr/local/下 192.168.1.101 2181 2287:3387 zookeeper-3.4.8 192.168.1.102 2181 2287:3387 zookeeper-3.4.8 192.168.1.103 2181 2287:3387 zookeeper-3.4.8

这里写图片描述

每台服务器做如下操作

cd /usr/localwget http://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.4.8/zookeeper-3.4.8.tar.gztar -zxvf zookeeper-3.4.8.tar.gzcp /usr/local/zookeeper-3.4.8/conf/zoo_sample.cfg /usr/local/zookeeper-3.4.8/conf/zoo.cfg

完成上述操作后,修改zoo.cfg配置文件成如下

tickTime=2000  initLimit=10  syncLimit=5  dataDir=/var/zookeeper/data  dataLogDir=/var/zookeeper/log  clientPort=2181  #2287为peer通信端口,3387为选举端口 server.1=192.168.1.101:2287:3387  server.2=192.168.1.102:2287:3387  server.3=192.168.1.103:2287:3387  

每个ZooKeeper的instance,都需要设置独立的数据存储目录、日志存储目录,所以dataDir节点对应的目录,需要手动先创建好

mkdir /var/zookeepermkdir /var/zookeeper/datamkdir /var/zookeeper/logtouch /var/zookeeper/data/myid

另外还有一个非常关键的设置,在每个zk server配置文件的dataDir所对应的目录下,必须创建一个名为myid的文件,其中的内容必须与zoo.cfg中server.x 中的x相同,即:

  • 192.168.1.101 服务器 /var/zookeeper/data/myid中的内容为1,对应server.1中的1
  • 192.168.1.102 服务器 /var/zookeeper/data/myid中的内容为2,对应server.2中的2
  • 192.168.1.103 服务器 /var/zookeeper/data/myid中的内容为3,对应server.3中的3

这里写图片描述

/usr/local/zookeeper-3.4.8/bin/zkServer.sh start /usr/local/zookeeper-3.4.8/bin/zkServer.sh stop/usr/local/zookeeper-3.4.8/bin/zkServer.sh status

验证集群状态

--MasterZooKeeper JMX enabled by defaultUsing config: /usr/local/zookeeper-3.4.8/bin/../conf/zoo.cfgMode: leader
--SlaveZooKeeper JMX enabled by defaultUsing config: /usr/local/zookeeper-3.4.8/bin/../conf/zoo.cfgMode: follower

这里写图片描述

touch /etc/init.d/zookeeper  chmod +x /etc/init.d/zookeeper

编辑zookeeper 文件如下内容

#!/bin/bash  #chkconfig:2345 20 90  #description:zookeeper  #processname:zookeeper  case $1 in            start) /usr/local/zookeeper-3.4.8/bin/zkServer.sh start;;            stop) /usr/local/zookeeper-3.4.8/bin/zkServer.sh stop;;            status) /usr/local/zookeeper-3.4.8/bin/zkServer.sh status;;            restart) /usr/local/zookeeper-3.4.8/bin/zkServer.sh restart;;            *)  echo "require start|stop|status|restart";;  esac 

添加服务

chkconfig --add zookeeper

设置开机启动

chkconfig --level 35 zookeeper on 

查看是否设置成功

[root@localhost ~]# chkconfig --list | grep zookeeperzookeeper       0:关闭  1:关闭  2:启用  3:启用  4:启用  5:启用  6:关闭

这里写图片描述

cd /usr/local/zookeeper-3.4.8/bin  ./zkCli.sh -timeout 5000 -server localhost:2181Connecting to localhost:21812017-04-22 08:21:34,876 [myid:] - INFO  [main:Environment@100] - Client environment:zookeeper.version=3.4.8--1, built on 02/06/2016 03:18 GMT2017-04-22 08:21:34,884 [myid:] - INFO  [main:Environment@100] - Client environment:host.name=localhost2017-04-22 08:21:34,884 [myid:] - INFO  [main:Environment@100] - Client environment:java.version=1.8.0_1112017-04-22 08:21:34,896 [myid:] - INFO  [main:Environment@100] - Client environment:java.vendor=Oracle Corporation2017-04-22 08:21:34,896 [myid:] - INFO  [main:Environment@100] - Client environment:java.home=/usr/local/jdk1.8.0_111/jre2017-04-22 08:21:34,897 [myid:] - INFO  [main:Environment@100] - Client environment:java.class.path=/usr/local/zookeeper-3.4.8/bin/../build/classes:/usr/local/zookeeper-3.4.8/bin/../build/lib/*.jar:/usr/local/zookeeper-3.4.8/bin/../lib/slf4j-log4j12-1.6.1.jar:/usr/local/zookeeper-3.4.8/bin/../lib/slf4j-api-1.6.1.jar:/usr/local/zookeeper-3.4.8/bin/../lib/netty-3.7.0.Final.jar:/usr/local/zookeeper-3.4.8/bin/../lib/log4j-1.2.16.jar:/usr/local/zookeeper-3.4.8/bin/../lib/jline-0.9.94.jar:/usr/local/zookeeper-3.4.8/bin/../zookeeper-3.4.8.jar:/usr/local/zookeeper-3.4.8/bin/../src/java/lib/*.jar:/usr/local/zookeeper-3.4.8/bin/../conf:.:/usr/local/jdk1.8.0_111/lib2017-04-22 08:21:34,898 [myid:] - INFO  [main:Environment@100] - Client environment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib2017-04-22 08:21:34,898 [myid:] - INFO  [main:Environment@100] - Client environment:java.io.tmpdir=/tmp2017-04-22 08:21:34,898 [myid:] - INFO  [main:Environment@100] - Client environment:java.compiler=<NA>2017-04-22 08:21:34,898 [myid:] - INFO  [main:Environment@100] - Client environment:os.name=Linux2017-04-22 08:21:34,899 [myid:] - INFO  [main:Environment@100] - Client environment:os.arch=amd642017-04-22 08:21:34,899 [myid:] - INFO  [main:Environment@100] - Client environment:os.version=2.6.32-431.el6.x86_642017-04-22 08:21:34,899 [myid:] - INFO  [main:Environment@100] - Client environment:user.name=root2017-04-22 08:21:34,902 [myid:] - INFO  [main:Environment@100] - Client environment:user.home=/root2017-04-22 08:21:34,903 [myid:] - INFO  [main:Environment@100] - Client environment:user.dir=/usr/local/zookeeper-3.4.8/bin2017-04-22 08:21:34,912 [myid:] - INFO  [main:ZooKeeper@438] - Initiating client connection, connectString=localhost:2181 sessionTimeout=5000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@531d72caWelcome to ZooKeeper!2017-04-22 08:21:35,003 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server localhost/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)JLine support is enabled2017-04-22 08:21:35,241 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@876] - Socket connection established to localhost/127.0.0.1:2181, initiating session2017-04-22 08:21:35,279 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x15b92ff5d4b0002, negotiated timeout = 5000WATCHER::WatchedEvent state:SyncConnected type:None path:null[zk: localhost:2181(CONNECTED) 0]

执行ls /,可以看到根下已有的目录结构,新搭建的服务只有/zookeeper

这里写图片描述

主机IP 集群通信端口 消息端口 控制台端口 节点目录/usr/local/下 192.168.1.101 61619 61616 8161 apache-activemq-5.13.2 192.168.1.102 61619 61616 8161 apache-activemq-5.13.2 192.168.1.103 61619 61616 8161 apache-activemq-5.13.2

这里写图片描述

cd /usr/localwget http://mirrors.noc.im/apache//activemq/5.13.2/apache-activemq-5.13.2-bin.tar.gztar -zxvf apache-activemq-5.13.2-bin.tar.gz

这里写图片描述

设置开机脚本文件

ln -s /usr/local/apache-activemq-5.13.2/bin/activemq /etc/init.d/activemqvi /etc/init.d/activemq 

在第二行插入如下两行语句

# chkconfig: 345 63 37  # description: Auto start ActiveMQ 

这里写图片描述

chkconfig --add activemq chkconfig --level 35 activemq on[root@localhost ~]# chkconfig --list | grep activemq activemq        0:关闭  1:关闭  2:关闭  3:启用  4:启用  5:启用  6:关闭

操作ActiveMQ

service activemq startservice activemq stopservice activemq restart

检测8161、61616端口是否在监听

[root@localhost ~]# netstat -tunpl | grep 8161tcp        0      0 :::8161                     :::*                        LISTEN      1412/java  [root@localhost ~]# netstat -tunpl | grep 61616tcp        0      0 :::61616                    :::*                        LISTEN      1412/java 

这里写图片描述

  • mq安装路径下的conf/activemq.xml进行mq的brokerName,并且每个节点名称都必须相同。
    这里写图片描述

    brokerName=”activemq-cluster”(三个节点都需要修改)

  • 释掉适配器中的kahadb
    这里写图片描述

  • 添加新的leveldb配置如下(三个节点都需要修改):

--NODE1<persistenceAdapter>    <!-- <kahaDB directory="${activemq.data}/kahadb"/> -->    <replicatedLevelDB        directory="${activemq.data}/leveldb"        replicas="3"        bind="tcp://0.0.0.0:61619"        zkAddress="192.168.1.101:2181,192.168.1.102:2181,192.168.1.103:2181"        hostname="192.168.1.101"        zkPath="/activemq/leveldb-stores"    /></persistenceAdapter>--NODE2<persistenceAdapter>    <!-- <kahaDB directory="${activemq.data}/kahadb"/> -->    <replicatedLevelDB        directory="${activemq.data}/leveldb"        replicas="3"        bind="tcp://0.0.0.0:61619"        zkAddress="192.168.1.101:2181,192.168.1.102:2181,192.168.1.103:2181"        hostname="192.168.1.102"        zkPath="/activemq/leveldb-stores"    /></persistenceAdapter>--NODE3<persistenceAdapter>    <!-- <kahaDB directory="${activemq.data}/kahadb"/> -->    <replicatedLevelDB        directory="${activemq.data}/leveldb"        replicas="3"        bind="tcp://0.0.0.0:61619"        zkAddress="192.168.1.101:2181,192.168.1.102:2181,192.168.1.103:2181"        hostname="192.168.1.103"        zkPath="/activemq/leveldb-stores"    /></persistenceAdapter>

到此为止,我们的activemq集群环境已经搭建完毕!

分别查看三台服务器的日志信息:

#192.168.1.101tail -f /usr/local/apache-activemq-5.13.2/data/activemq.log#192.168.1.102tail -f /usr/local/apache-activemq-5.13.2/data/activemq.log#192.168.1.103tail -f /usr/local/apache-activemq-5.13.2/data/activemq.log

如果不报错,我们的集群启动成功

这里写图片描述

使用ZooKeeper(集群)注册所有的ActiveMQ Broker。只有其中的一个Broker可以提供服务,被视为Master,其他的 Broker 处于待机状态,被视为Slave

如果Master因故障而不能提供服务,Zookeeper会从Slave中选举出一个Broker充当MasterSlave连接Master并同步他们的存储状态,Slave不接受客户端连接。所有的存储操作都将被复制到 连接至 MasterSlaves

如果Master宕了,得到了最新更新的Slave会成为Master。故障节点在恢复后会重新加入到集群中并连接Master进入Slave模式。

当集群运行时,只有一个为Master可用,控制台可访问,有队列,订阅主题消息,而Slave上没有,只有在Master宕机时,重新选举的Master从源Master拷贝消息,Slave与新的Master连接,同步leveldb索引信息。

#集群的brokerUrl配置failover:(tcp://192.168.1.101:61616,tcp://192.168.1.102:61616,tcp://192.168.1.103:61616)?Randomize=false

在Eclipse环境下安装ZooKeeper状态查看相关的插件步骤如下:

 1. 在 Eclipse 菜单打开Help -> Install New Software… 2. 添加 url http://www.massedynamic.org/eclipse/updates/ 3. 选择插件并安装运行 4. 在 Eclipse 菜单打开Window->Show View->Other…->ZooKeeper 3.2.2 5. 连接ZK 输入正在运行的ZK server 地址和端口

连接成功后就就可以在Eclipse里查看ZK Server里的节点信息。如下所示:

这里写图片描述

这里写图片描述

单点的ActiveMQ作为企业应用无法满足高可用和集群的需求,所以ActiveMQ提供了master-slave、broker cluster等多种部署方式,但通过分析多种部署方式之后我认为需要将两种部署方式相结合才能满足我们公司分布式和高可用的需求,所以后面就重点将解如何将两种部署方式相结合。

这里写图片描述

这里写图片描述

这种方式Slave的个数没有限制,哪个ActiveMQ实例先获取共享文件的锁,那个实例就是Master,其它的ActiveMQ实例就是Slave,当当前的Master失效,其它的Slave就会去竞争共享文件锁,谁竞争到了谁就是Master。此模式结构图如下:

这里写图片描述

这里写图片描述

与shared file system方式类似,只是共享的存储介质由文件系统改成了数据库而已。

这里写图片描述

这种主备方式是ActiveMQ5.9以后才新增的特性,使用zooKeeper协调选择一个node作为Master。被选择的Master broker node开启并接受客户端连接。

其他node转入Slave模式,连接Master并同步他们的存储状态。Slave不接受客户端连接。所有的存储操作都将被复制到连接至Master的Slaves。

如果Master死了,得到了最新更新的slave被允许成为Master。fialed node能够重新加入到网络中并连接Master进入Slave node。所有需要同步的disk的消息操作都将等待存储状态被复制到其他法定节点的操作完成才能完成。所以,如果你配置了replicas=3,那么法定大小是(3/2)+1=2. Master将会存储并更新然后等待 (2-1)=1个Slave存储和更新完成,才汇报success。至于为什么是2-1,熟悉zookeeper的应该知道,有一个node要作为观擦者存在。

单一个新的Master被选中,你需要至少保障一个法定node在线以能够找到拥有最新状态的node。这个node将会成为新的Master。因此,推荐运行至少3个replica nodes,以防止一个node失败了,服务中断。

这里写图片描述

可以看到Master-Slave的部署方式虽然解决了高可用的问题,但不支持负载均衡,Broker-Cluster解决了负载均衡,但当其中一个Broker突然宕掉的话,那么存在于该Broker上处于Pending状态的message将会丢失,无法达到高可用的目的。

由于目前ActiveMQ官网上并没有一个明确的将两种部署方式相结合的部署方案,所以我尝试者把两者结合起来部署:

这里写图片描述

这里写图片描述

在activemq.xml文件中静态指定Broker需要建立桥连接的其他Broker:

Broker Master Slave Slave Broker-A 192.168.1.101 192.168.1.102 192.168.1.103 Broker-B 192.168.1.104 192.168.1.105 192.168.1.106 Broker-C 192.168.1.107 192.168.1.108 192.168.1.109

这里写图片描述

<networkConnectors>     <networkConnector uri="static:(tcp://192.168.1.104:61616,tcp://192.168.1.105:61616,tcp://192.168.1.106:61616)" duplex="false"/>    <networkConnector uri="static:(tcp://192.168.1.107:61616,tcp://192.168.1.108:61616,tcp://192.168.1.109:61616)" duplex="false"/></networkConnectors>

这里写图片描述

<networkConnectors>     <networkConnector uri="static:(tcp://192.168.1.101:61616,tcp://192.168.1.102:61616,tcp://192.168.1.103:61616)" duplex="false"/>    <networkConnector uri="static:(tcp://192.168.1.107:61616,tcp://192.168.1.108:61616,tcp://192.168.1.109:61616)" duplex="false"/></networkConnectors>

这里写图片描述

<networkConnectors>     <networkConnector uri="static:(tcp://192.168.1.101:61616,tcp://192.168.1.102:61616,tcp://192.168.1.103:61616)" duplex="false"/>    <networkConnector uri="static:(tcp://192.168.1.104:61616,tcp://192.168.1.105:61616,tcp://192.168.1.106:61616)" duplex="false"/></networkConnectors>

这里写图片描述

在activemq.xml文件中不直接指定Broker需要建立桥连接的其他Broker,由activemq在启动后动态查找:

这里写图片描述

<networkConnectors>     <networkConnectoruri="multicast://default"           dynamicOnly="true"           networkTTL="3"           prefetchSize="1"           decreaseNetworkConsumerPriority="true" /></networkConnectors>

这里写图片描述

<networkConnectors>     <networkConnectoruri="multicast://default"           dynamicOnly="true"           networkTTL="3"           prefetchSize="1"           decreaseNetworkConsumerPriority="true" /></networkConnectors>

这里写图片描述

<networkConnectors>     <networkConnectoruri="multicast://default"           dynamicOnly="true"           networkTTL="3"           prefetchSize="1"           decreaseNetworkConsumerPriority="true" /></networkConnectors>
0 0
原创粉丝点击