1、综述
通过之前的文章,我们讨论了ActiveMQ的基本使用,包括单个ActiveMQ服务节点的性能特征,关键调整参数;我们还介绍了单个ActiveMQ节点上三种不同的持久化存储方案,并讨论了这三种不同的持久化存储方案的配置和性能特点。但是这还远远不够,因为在生产环境中为了保证让我们设计的消息服务方案能够持续工作,我们还需要为消息中间件服务搭建集群环境,从而在保证消息中间件服务可靠性和处理性能。
2、ActiveMQ多节点方案
集群方案主要为了解决系统架构中的两个关键问题:高可用和高性能。ActiveMQ服务的高可用性是指,在ActiveMQ服务性能不变、数据不丢失的前提下,确保当系统灾难出现时ActiveMQ能够持续提供消息服务,高可靠性方案最终目的是减少整个ActiveMQ停止服务的时间。
ActiveMQ服务的高性能是指,在保证ActiveMQ服务持续稳定性、数据不丢失的前提下,确保ActiveMQ集群能够在单位时间内吞吐更高数量的消息、确保ActiveMQ集群处理单条消息的时间更短、确保ActiveMQ集群能够容纳更多的客户端稳定连接。
下面我们分别介绍如何通过多个ActiveMQ服务节点集群方式,分别提供热备方案和高性能方案。最后我们讨论如何将两种方案结合在一起,最终形成在生成环境下使用的推荐方案。
2-2、ActiveMQ高性能方案
ActiveMQ的多节点集群方案,主要有动态集群和静态集群两种方案。所谓动态集群就是指,同时提供消息服务的ActiveMQ节点数量、位置(IP和端口)是不确定的,当某一个节点启动后,会通过网络组播的方式向其他节点发送通知(同时接受其他节点的组播信息)。当网络中其他节点收到组播通知后,就会向这个节点发起连接,最终将新的节点加入ActiveMQ集群;所谓静态集群是指同时提供消息服务的多个节点的位置(IP和端口)是确定的,每个节点不需要通过广播的方式发现目标节点,只需要在启动时按照给定的位置进行连接。
静态集群方案
动态集群方案
2-1-1、基于组播(multicast)的节点发现
在使用动态集群配置时,当某个ActiveMQ服务节点启动后并不知道整个网络中还存在哪些其他的服务节点。所以ActiveMQ集群需要规定一种节点与节点间的发现机制,以保证能够解决上述问题。ActiveMQ集群中,使用“组播”原理进行其他节点的发现。
组播(multicast)基于UDP协议,它是指在一个可连通的网络中,某一个数据报发送源向一组数据报接收目标进行操作的过程。在这个过程中,数据报发送者只需要向这个组播地址(一个D类IP)发送一个数据报,那么加入这个组播地址的所有接收者都可以收到这个数据报。组播实现了网络中单点到多点的高效数据传送,能够节约大量网络带宽,降低网络负载。
在IP协议中,规定的D类IP地址为组播地址。224.0.0.0~239.255.255.255这个范围内的IP都是D类IP地址,其中有一些IP段是保留的有特殊含义的:
224.0.0.0~224.0.0.255:这个D类IP地址段为保留地址,不建议您在开发过程中使用,因为可能产生冲突。例如224.0.0.5这个组播地址专供OSPF协议(是一种路由策略协议,用于找到最优路径)使用的组播地址;224.0.0.18这个组播地址专供VRRP协议使用(VRRP协议是虚拟路由器冗余协议)。
224.0.1.0~224.0.1.255:这个D类IP地址为公用组播地址,用于在整个Internet网络上进行组播。除非您有顶级DNS的控制/改写权限,否则不建议在局域网内使用这个组播地址断。
239.0.0.0~239.255.255.255:这个D类IP地址段为推荐在局域网内使用的组播地址段。注意,如果要在局域网内使用组播功能,需要局域网中的交换机/路由器支持组播功能。幸运的是,目前市面上只要不是太过低端的交换机/路由器,都支持组播功能(组播功能所使用的主要协议为IGMP协议,关于IGMP协议的细节就不再进行深入了)。
下面我们使用java语言,编写一个局域网内的组播发送和接受过程。以便让各位读者对基于组播的节点发现操作有一个直观的理解。虽然ActiveMQ中关于节点发现的过程,要比以下的示例复杂得多,但是基本原理是不会改变的。
- 组播数据报发送者:
package multicast;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Date;
public class SendMulticast {
public static void main(String[] args) throws Throwable {
// 组播地址
InetAddress group = InetAddress.getByName("239.0.0.5");
// 组播端口,同时也是UDP 数据报的发送端口
int port = 19999;
MulticastSocket mss = null;
// 创建一个用于发送/接收的MulticastSocket组播套接字对象
mss = new MulticastSocket(port);
// 创建要发送的组播信息和UDP数据报
// 携带的数据内容,就是这个activeMQ服务节点用来提供Network Connectors的TCP/IP地址和端口等信息
String message = "我是一个活动的activeMQ服务节点(节点编号:yyyyyyy),我的可用tcp信息为:XXXXXXXXXX : ";
byte[] buffer2 = message.getBytes();
DatagramPacket dp = new DatagramPacket(buffer2, buffer2.length, group, port);
// 使用组播套接字joinGroup(),将其加入到一个组播
mss.joinGroup(group);
// 开始按照一定的周期向加入到224.0.0.5组播地址的其他ActiveMQ服务节点进行广播
Thread thread = Thread.currentThread();
while (!thread.isInterrupted()) {
// 使用组播套接字的send()方法,将组播数据包对象放入其中,发送组播数据包
mss.send(dp);
System.out.println(