为什么要对消息中间件集群?
- 实现高可用,以排除单点故障引起的服务中断
- 实现负载均衡,以提升效率为更多客户端提供服务
ActiveMQ集群基础知识
- 集群方式:
- 客户端集群:让多个消费者消费同一队列(在队列模式下消息本身支持多个消费者负载,在主题模式下多个消费者消费的是完整的消息,这将造成消息重复的可能)
- Broker Clusters:通过多个Broker之间同步消息以达到服务器负载的可能
- Master Slave集群:实现高可用(当主消息服务器宕机时,备用服务器可以成为主服务代替)
- 客户端配置
- ActiveMQ失效转移(failover)
ActiveMQ提供失效转移机制,用于客户端创立连接时,它允许当一台消息服务器宕机时,客户端在传输层上重新连接到其他消息服务器。 - 语法:failover:(uri1,…,uriN)?transportOptions
- 说明:uri是消息服务器的地址
- transporrtOptions传输参数说明:
randomize默认是true,表示在URI列表中选择连接时是否采用随机策略
initialReconnectDelay:默认是10,单位毫秒,表示第一次尝试重连之间的等待时间
maxReconnectDelay:默认30000,单位毫秒,最长重连的时间间隔
- Broker Cluster集群配置
- 原理:
如下图有两个节点,节点A和节点B,节点A可以把消息同步到节点B,节点B也可以把消息同步到节点A,通过消息同步之后,节点A接收到的消息可以被节点B的消费者消费,节点B接收到的消息也可以被节点A的消费者消费 - 实现方式是采用NetworkConnector网络连接器:
网络连接器主要用于配置ActiveMQ服务器与服务器之间的网络通讯方式,用于服务器透传消息
网络连接器分为静态连接器和动态连接器 - 静态连接器:是在配置中指定服务器的具体ip信息
<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>
传输连接器中配置了一个发现的uri地址,这个就是主波地址,这样就可以达到动态扩展服务器的效果
- Master/Slave集群配置
- 集群方案:
- 没有共享存储的主备方案 share nothing storage master/slave(已过时,5.8+后移除,存在很多局限性)
- 共享存储的主备方案 shared storage master/slave (此方案中节点获取到消息储存排他锁就可以成为master,而没有获取到资源锁的节点将成为slave,当master待机的时候释放资源锁,而被slave获取到后就成为了新的master,目前ActiveMQ支持基于san文件系统和基于jdbc数据库表级排他锁的两种方式)
- 基于复制的LevelDB Store Replicated LevelDB Store(高可用存储引擎)
在使用共享存储主备方案其实是使用了一些小伎俩来完成的Master/Slave, 不符合广泛意义上的Master/Slave,而基于复制的LevelDB Store做到了这一点,这种方案主要使用zk来选举Master,每个Broker将消息保存到本地,它们之间不共享任何数据,它们之间的数据同步通过zk来传递,用zk来保证集群的稳定,这要求开发者至少部署三个broker,而zk本身也至少需要三台服务器来完成集群才能保证zk自身的稳定性,如果不保证zk的稳定性,如果zk的集群出现问题那我们整个服务器集群就蹦掉了
- 原理:
- 共享存储集群的原理
有节点A和节点B两台服务器,使用了一个共享的储存地址称之为持久化,它可以是jdbc的数据库,也可以是基于san的文件系统,然后将节点A和节点B的持久化配置都配置到同一个地方之后,先启动节点A,这个时候它获取到了资源排他锁成为Master,再启动节点B,这时候它获取不到所资源成为了slave,成为了Master的服务器就是获取到了对外开放服务的能力,可以通过外部的客户端提交信息到节点A,但是不能发送到节点B,如下图:
如果此时节点A挂掉,此时节点B立即获取到持久化资源的排他锁成为了新的Master,接收外部客户端的请求,客户端使用失效转移之后将请求发送到了B,完成了整个请求的不间断性,达到了高可用的效果。
如下图: - 基于复制的LevelDB Store的原理(因为它基于zk,所以至少要三台服务器)
首先有三台服务器,分别是节点A,节点B,节点C,每个服务器节点都有自己的储存方式,因为配置了同一个zk节点,通过zk来选举一台服务器作为Master,如下图:
假设选举节点A作为Master,这时候节点A就具有了对外提供服务的能力,节点B和C不具备对外提供的能力,节点A获取到外部服务的消息资源之后他在本地储存,然后通过zk把消息同步给B和C,B和C分别在自己的服务器上储存,如果节点A出现故障,zk会立即重新选举一台Master
两种集群方式的对比:
项目 | 高可用 | 负载均衡 |
Master/Slave | 是 | 否 |
Broker Cluster | 否 | 是 |
master/slave可以做到高可用,因为一台服务器挂掉之后另外一台服务器立即补充,保证了他的消息不会丢失,但是做不了负载均衡,因为slave服务器不具备外部提供服务的能力
Broker Cluster不具备高可用的能力,因为他自己的消息并没有在一个地方储存, 换句话说就是当这台服务器挂掉之后,它正在处理的消息会同步丢失。但是做到了负载均衡。
如何做到既可以具备高可用又能做到负载均衡呢?
下面展示三台服务器的完美集群方案:
有三个节点A,B,C,将节点A和节点B组成消息同步,节点A和节点C组成消息同步,节点B和节点C组成Master/Slave ,按顺序启动节点ABC。这个时候B获取持久化的资源成为Master,C成为了Slave,A成了B的消息同步服务器,因为A
没有持久化的配置,消息将通过B完成持久化,A或者B接收的消息都可以被负载消费,达成了负载均衡和高可用的要求。
分析:假设节点A挂掉,节点B还能继续提供服务,整个集群不受影响,当恢复了节点A之后,节点B上面的消息可以被节点A消费,节点A上面新收到的消息也能被节点B消费,集群不受影响,假如节点B挂掉,节点C会获取持久化资源成为新的Master,用来接受客户端的请求,节点c可以持久化节点A和C上面的消息,节点A和C也能负载消息,节点B恢复之后,成为Slave等待资源锁。整个集群不受影响,符合高可用和负载均衡的要求,假如节点C挂掉,因为本身是Slave对集群没影响。
注意:当一台服务器挂掉之后要立即恢复,当两台服务器一起宕机的时候集群就崩掉了,所以要用更多的服务器做到集群的稳定。