ActiveMQ 简单集群
慕课网Java消息中间件笔记
ActiveMQ集群配置
为什么要配置消息中间件集群
- 实现高可用,以排除单点故障引起的服务中断。
- 实现负载均衡,以提升效率为更多客户提供服务。
ActiveMQ集群基础知识
集群方式
- 客户端集群:让多个消费者消费同一个队列
在队列模式下,默认支持多个消费者负载;但在主题模式下,多个消费者消费的是完整的消息,这将出现消息重复的可能,需要解决该问题。 - Broker clusters:多个Broker之间同步消息,以达到服务器负载。
- Master Slave:实现高可用。
当master宕机时,slave可以立即补充,以保证服务的继续。
客户端配置
- ActiveMQ失效转移(failover)
允许当其中一台消息服务器宕机时,客户端在传输层上重新连接到其他消息服务器。
语法:
failover:(uri1,...,uriN)?transportOptions
transportOptions参数说明
1、randomize:默认为true,表示在URI列表中选择URI连接时是否采用随机策略。
2、initialReconnectDelay:默认为10,单位毫秒。表示第一次尝试重连之间的等待时间。
3、maxReconnectDelay:默认30000,单位毫秒。最长重连的时间间隔。
Broker Cluster集群配置
- 原理
当有节点A、节点B。他们互相可以同步消息。通过同步之后,节点A接收到的消息可以被节点B的消费者消费,反之亦然。
它的实现方式是采用网络连接器。 - 网络连接器(NetworkConnector)
网络连接器主要用于配置ActiveMQ服务器与服务器之间的网络通讯方式,用于服务器透传消息。
网络连接器分为静态连接器和动态连接器。 -
静态连接器
在服务器的IP地址上面去指定具体的IP地址。动态扩展不方便。
静态连接器配置 -
动态连接器
动态连接器
集群方案
ActiveMQ Master Slave 集群方案
- Share nothing storage master/slave(已过时,5.8+ 版本后移除)
- Shared storage master/slave 共享存储主从方案
节点获取到消息,储存排他锁,成为master;没有获取到排他锁的节点成为slave。当master宕机时,释放排他锁,此时slave获取到排他锁成为新的master。 - Replicated LevelDB Store基于复制的LevelDB Store
使用ZooKeeper来选举master,每个Broker将消息保存到本地,他们之间不共享任何数据,Broker之间的数据通过ZooKeeper传递,用ZooKeeper保持集群稳定,这要求我们至少部署三台Broker。而ZooKeeper本身也至少需要三台服务器来搭建集群以保证ZooKeeper自身的稳定性。
共享存储集群(Shared storage master/slave)的原理
有节点A、节点B两台服务器,并使用一个共享的存储地址,称之为持久化,它可以是JDBC数据库也可以是基于SAN的文件系统(SAN File System)。
将节点A和节点B的持久化地址都配置到同一个地方之后,先启动节点A,此时节点A获得了排他锁成为master;再启动节点B,由于节点B未获取到排他锁,因此成为slave。
节点A成为master
成为master的服务器具有对外开放服务的能力,可以通过客户端提交信息到节点A,但是不能提交到节点B。
此时A宕机,节点B获取到了排他锁成为master,客户端使用失效转移后,将请求发送到了节点B。实现了请求不间断的高可用。
节点B成为master
基于复制的LevelDB Store的原理
由于LevelDB是基于ZooKeeper的,所以至少需要3台服务器节点:Node A、Node B、Node C,他们都有自己的初始化方式,并配置了相同的ZK节点,通过ZK来选举一台服务器作为master。
假如Node A被选举为master,此时它具有对外提供服务的能力,而Node B和Node C不具备。Node A获取外部消息资源之后在本地储存,通过ZK再发送给Node B和Node C,并在他们的本地储存。
如果Node A出现故障,ZK会重新选举出一个master。
两种集群方式对比
- Master/Slave
可以做到高可用,因为一台服务器宕机,另一台服务器会立刻补充,保证消息不丢失,但它无法做到负载均衡,因为slave服务器不具备对外提供服务的能力。 - Broker Cluster
不具备高可用能力,因为它自己的消息并没有在一个地方储存,如果这台服务器宕机,它正在处理的消息可能会丢失;但是它可以做到负载均衡。
简单实现完美集群方案——共享持久化资源方式
节点A和节点B、节点A和节点C组成消息同步;节点B和节点C组成Master和Slave。
image.png
按A、B、C的顺序启动服务器
此时节点B拿到持久化资源成为master,节点C成为slave。
- 若节点A宕机
节点B为master可以对外提供服务。当节点A恢复后,节点B上的消息可以被A消费,节点A的消息也可以被B消费。 - 若节点B宕机
B会释放资源锁,C会得到资源锁并成为新的master,并获得对外服务的能力,且A、C之间互相同步和消费资源不受影响;当B恢复,它就成为新的slave。 - 若C宕机
由于C本身是slave,所以宕机后对整体没有影响。
虽然上述方案当任何一台机器宕机时对服务没有影响,但要立即恢复宕机的服务器。若同时有两台服务器宕机,则整体服务崩溃,因此需要添加更多的节点保证高可用。
简单集群的实现
安装三份ActiveMQ
由于是在单台服务器演示,所以通过修改端口来实现多节点配置。
解压ActiveMQ并复制三份,分别命名为activemq-a、activemq-b、activemq-c
image.png
创建共享储存文件夹
新建一个文件夹作为节点共享的存储文件夹。
$ mkdir kahadb
分别配置节点
修改activemq目录下的/conf/activemq.xml文件。
activemq配置文件
节点A -- activemq-a
找到transportConnector
节点,只保留61616端口配置,其余的协议注释掉。
- 配置网络连接器
添加networkConnectors
节点。网络连接器支持静态发现和动态发现,由于这里只是固定的三台服务器,因此这里采用静态发现。分别将B、C节点的地址配置进去(B节点使用61617端口,C节点使用61618端口)。
配置网络连接器 -
配置jetty
编辑jetty.xml文件
由于A节点采用默认配置,所以暂且不需要修改配置文件。
jetty
节点B -- activemq-b
同样也是注释掉其他协议,保留第一个,同时将端口改为61617
节点B配置
-
配置网络连接器
这次指定A节点的地址
指定A节点地址 -
配置共享文件目录
该路路径直接指向我们之前创建的用作存储共享数据的文件夹。
配置共享文件目录 -
配置jetty
端口改为8162
端口8162
节点C -- activemq-c
C节点配置过程同B一样。端口修改为61618和8163,网络连接器uri指向A节点 url="static:(tcp://127.0.0.1:61616)"
按A、B、C的顺序启动节点
依次启动A、B、C节点-
观察端口监听状态
查看以下节点A(61616)、节点B(61617)、节点C(61618)的端口监听状态。
端口状态
发现节点A和节点C都以开启监听,但节点C却没有开启。这是因为B、C节点互为Master/Slave,B优先于C启动并获得了资源锁成为Master,因此作为Slave的C不具备对外提供服务的能力。
-
关闭B节点并观察C节点是否提供服务
B节点关闭后,释放资源锁,C节点获取资源锁并成为Master,开始对外提供服务。
C节点端口已被监听 -
再启动B节点
因为此时C节点为Mater,当B节点恢复后,没有拿到资源锁,因此成为C的Slave,同时也不具备对外提供服务的能力。
B节点成为Slave
代码验证
-
提供者
failver:代表状态转移,此处配的是B节点和C节点的地址,这样当其中一个节点出现问题时,会自动连接到另一个节点。
randomize:表示在url列表中随机选择一台连接。
集群配置 -
消费者
由于三个节点都可作为消费者,所以都配置到了url列表中。
消费者
测试
-
启动消息提供者发送消息
从控制台可以看到程序已经连接到61618,也就是我们C节点。
成功连接到C节点
进入到C节点后台(192.168.58.3:8163),100条消息已经在队列中了。
C节点后台
此时我们尝试进入B节点后台,发现B节点没有提供服务。(因为B节点此时为slave,C节点为master)
B节点没有提供服务 -
尝试关闭C节点,并观察B节点状态
我们关闭C节点,再尝试进入B节点后台,发现成功进入,代表B节点自动开始提供服务,并且之前发送的100条消息也存在于B节点中。
B节点提供服务 -
启动消费者
启动消费后发现从我们配置的三台节点中随机选取到了B节点消费。
启动消费者
查看连接状态
在ActiveMQ后台的Connections和Network选项中可以查看服务器的连接状态。