ActiveMQ Master Slave集群

人生是海洋,希望是舵手的罗盘,使人们在暴风雨中不致迷失方向。 —— 狄德罗

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&amp;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&amp;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。


activemq1启动时获得锁,且连接数据库成功

activemq2一直阻塞在等待锁

activemq1宕机后,activemq2立即获得锁,然后连接数据库成功

  启动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。


Master启动日志

  随后启动的Broker都会成为slave。


slave1启动日志

slave2启动日志

  当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服务节点的位置,并以“,”进行分隔。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容