为什么要对消息中间件集群?
实现高可用,以排除单点故障引起的服务中断
实现负载均衡,以提升效率为更多用户提供服务
集群方式:
客户端集群:让多个消费者消费同一个队列
Broker clusters:多个Broker之间同步消息
Master Slave:实现高可用
客户端配置:
ActiveMQ失效转移(falilover):
允许当其中一台消息服务器宕机时,客户端在传输层上重新连接到其他消息服务器。
语法:failover:(uri1,....,uriN)?transportOptions
transportOptions参数说明:
randomize:默认为true,表示在URI列表中选择URI连接时是否采用随机策略
initialReconnectDelay:默认10毫秒,表示第一次尝试重连之间等待的时间
maxReconnectDelay:默认30000毫秒,表示最长重连的时间间隔
Broker clusters集群配置:
原理:两个节点,节点A和节点B,节点A可以把消息同步到节点B,节点B可以把消息同步到节点A,同步之后,节点A接收到的消息可以被节点B的消费者消费,反之亦然,其实现方式是通过"网络连接器"来实现的。
网络连接器:网络连接器主要用于配置ActiveMQ服务器与服务器之间的网络通讯方式,用于服务器透传消息。又分为静态连接器和动态连接器。
静态连接器配置:
<networkConnectors>
<networkConnector uri="static:(tcp://127.0.0.1:61617,tcp://127.0.0.1:61618)"/>
</networkConnectors>
动态连接器配置:
<networkConnectors>
<networkConnector uri="multicast://default"/>
</networkConnectors>
<transportConnectors>
<transportConnector uri="tcp://localhost:0" discoveryUri="multicast://default"/>
</transportConnectors>
Master Slave集群配置:
ActiveMQ Master Slave集群方案:
1.Shared storage master/slave 共享存储
2.Replicated LevelDB Store 基于复制的LevelDB Store
共享存储集群的原理:
比如有两台服务器节点A和节点B,他们有一个共享的持久化地址,先启动节点A,A获得排它锁独占资源成为Master,B成为Slave,若A挂掉,B将获得持久化资源的排它锁成为Master接收客户端的请求,客户端通过失效转移将请求发送到了B,完成了请求的不间断性,达到高可用效果。
基于复制的LevelDB Store的原理:
因为LevelDB是基于ZK的,所以它的服务器至少有三个,每个节点都有自己的储存化方式,他们共有一个zk节点,通过zk来选取一台服务器作为Master,A就具有了提供给外部服务的能力,获得外部消息资源后在本地"store"储存,再通过zk将消息同步给B和C储存起来,若A故障,zk会选取另一台服务器成为Master。
两种集群方式的对比
Master/Slave实现了高可用,因为一台服务器挂掉,另一台服务器可以马上顶替上去,且保证了消息不会丢失,但是无法做到负载均衡,因为Slave服务器不能提供服务。
Broker Cluster不能实现高可用,因为它获得的消息没有做持久化,若某个服务器挂掉,它正在处理的消息就会丢失,但是做到了负载均衡,因为A节点的消息可以被节点B的消费者消费,B节点的消息可以被节点A的消费者消费。
如何做到两者兼备呢?
下面是网上找的一种三台服务器的完美集群方案:
无论A,B,C哪个服务器宕机,都不会影响服务的正常运行,保证了高可用,又因为B、C和A之间的消息同步,实现了B、A或C、A之间可以互相消费彼此的消息,实现了负载均衡。
ActiveMQ三台服务器的完美集群具体配置方案:
因为只有一台电脑,所以只能通过开放不同端口的方法来实现一台电脑部署三个服务器
先新建三个actvemq服务目录activemq-A,activemq-B,activemq-C,一个持久化目录share-DB
将apache-activemq-5.14.2复制进A,B,C三个目录中
进入activemq-A的apache-activemq-5.14.2的conf,编辑activemq.xml
将除了端口61616的配置注释掉
添加网络连接器配置,将B,C的uri添加进来:
还需要编辑conf目录下的jetty.xml(提供后端管理地址的jetty服务器)
因为A节点使用的就是默认的8161端口,因此不用修改
以下是B节点activemq.xml的配置:
这是持久化目录的配置
<persistenceAdapter>
<kahaDB directory="/opt/app/actvemq/share-DB"/>
</persistenceAdapter>
网络连接器的配置:
<transportConnector name="openwire" uri="tcp://0.0.0.0:61617?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<!--<transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="stomp" uri="stomp://0.0.0.0:61613?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:61614?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>-->
</transportConnectors>
<networkConnectors>
<networkConnector name="network_A" uri="static:(tcp://127.0.0.1:61616)"/>
</networkConnectors>
jetty服务端口则改为8162
C节点配置就不一一展示了,模仿B节点修改就行。
最后依次启动A,B,C节点,查看相应端口,可以看出因为先启动activemq-B所以它成为Master,C节点成为Slave不提供服务(进程状态TiIME_WAIT)
用我的博客"简单使用ActiveMQ"里的代码进行测试,不过还要进行客户端失效转移的配置,很简单就修改两处地方:
AppPoducer.java:
private static final String url="failover:(tcp://127.0.0.1:61617,tcp://127.0.0.1:61618)?randomize=true";
AppConsumer.java:
private static final String url="failover:(tcp://127.0.0.1:61616,tcp://127.0.0.1:61617,tcp://127.0.0.1:61618)?randomize=true";