在当今分布式系统盛行的时代,消息中间件扮演着至关重要的角色,而 ActiveMQ 作为一款开源的、功能强大的消息中间件,在众多项目中得到了广泛应用。它支持多种消息传输协议,如 JMS、AMQP、MQTT 等 ,能够方便地实现系统之间的异步通信,有效解耦不同的业务模块,提升系统的可靠性和灵活性。
随着业务的不断发展和用户量的持续增长,对消息中间件的性能、可靠性和可用性提出了更高的要求。单节点的 ActiveMQ 在面对高并发、大规模数据传输以及硬件故障等情况时,往往显得力不从心。例如,在电商促销活动期间,大量的订单消息、库存变更消息等需要及时处理,如果单节点 ActiveMQ 出现故障,可能会导致订单丢失、库存数据不一致等严重问题,给企业带来巨大的经济损失。
为了应对这些挑战,搭建 ActiveMQ 集群并设计高可用方案成为了必然选择。通过集群部署,可以实现负载均衡,将大量的消息请求均匀地分配到各个节点上,避免单个节点因负载过高而出现性能瓶颈。同时,集群中的多个节点可以相互备份,当某个节点发生故障时,其他节点能够迅速接管其工作,保证消息的可靠传输和系统的持续运行,从而大大提高了系统的可用性和容错能力 。
在接下来的内容中,我们将深入探讨 ActiveMQ 集群搭建的详细步骤以及高可用方案的设计与实现,希望能为大家在实际项目中应用 ActiveMQ 提供有价值的参考。
ActiveMQ 是 Apache 软件基金会下的一款开源的消息中间件,基于 Java 语言开发 ,能够在分布式系统中高效地实现消息的发送和接收。它支持多种消息传输协议,像 JMS(Java Message Service)、AMQP(Advanced Message Queuing Protocol)、MQTT(Message Queuing Telemetry Transport) 等,这使得它可以在不同的技术架构和应用场景中灵活应用。
ActiveMQ 具备多种特性,为企业级应用提供了可靠的消息通信支持。它支持多种语言编写客户端,包括 Java、C、C++、C#、Ruby、Perl、Python、PHP 等,方便不同技术栈的开发团队进行集成。同时,ActiveMQ 完全支持 JMS1.1 和 J2EE 1.4 规范,涵盖了持久化、XA 消息、事务等重要功能,确保了消息的可靠传输和事务一致性 。在消息持久化方面,ActiveMQ 支持通过 JDBC 和 journal 提供高速的消息持久化,保证消息在系统故障等情况下不丢失。并且,它从设计上保证了高性能的集群、客户端 - 服务器、点对点的通信模式,能够满足不同业务场景下的通信需求。
在应用场景方面,ActiveMQ 有着广泛的应用。在电商系统中,当用户下单后,订单系统可以将订单消息发送到 ActiveMQ 队列,库存系统、物流系统等作为消费者从队列中获取消息并进行相应处理,如库存扣减、物流单生成等,实现了不同业务系统之间的解耦和异步通信。在分布式系统的日志处理中,各个服务产生的日志信息可以通过 ActiveMQ 发送到日志收集系统,由日志收集系统统一进行存储和分析,提高了日志处理的效率和灵活性 。在消息推送场景中,如新闻资讯推送、即时通讯消息推送等,ActiveMQ 可以作为消息的中转站,将消息推送给多个订阅者,实现一对多的消息广播。
export JAVA_HOME=/usr/local/jdk1.8.0_311 # 根据实际安装路径修改
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
配置完成后,执行source /etc/profile命令使配置生效 。
# 开放8161端口策略
firewall - cmd --zone = public --add - port = 8161/tcp --permanent
# 开放61616端口策略
firewall - cmd --zone = public --add - port = 61616/tcp --permanent
# 重新载入防火墙策略
firewall - cmd --reload
启动成功后,可以通过http://服务器IP:8161/admin访问 ActiveMQ 的管理页面,默认用户名和密码都是admin 。
ActiveMQ 的主要配置文件是conf/activemq.xml,该文件包含了 ActiveMQ 的各种核心配置参数 。
在集群环境中,通常会使用基于 Zookeeper 和 LevelDB 的持久化方式,这种方式能够提供更好的高可用性和数据一致性。配置示例如下:
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:62222"
zkAddress="192.168.1.100:2181,192.168.1.101:2181,192.168.1.102:2181"
hostname="192.168.1.100"
zkPath="/activemq/leveldb-stores/"/>
其中,directory指定了 LevelDB 数据存储目录;replicas表示集群中的节点数量,一般设置为奇数,以确保在节点故障时能够正常选举出主节点;bind指定了集群内部通信的端口;zkAddress指定了 Zookeeper 集群的地址;hostname指定了当前节点的 IP 地址;zkPath指定了 ActiveMQ 在 Zookeeper 中存储选举信息和数据同步的路径 。
4. transportConnectors 元素:transportConnectors元素用于配置 ActiveMQ 的传输连接器,定义了客户端与 ActiveMQ 代理进行通信的协议和端口。例如,配置 TCP 协议的传输连接器:
其中,name指定了传输连接器的名称;uri指定了通信的协议(这里是 TCP)、地址(0.0.0.0表示监听所有 IP 地址)和端口(61616),还可以设置一些参数,如maximumConnections表示最大连接数,wireFormat.maxFrameSize表示最大帧大小 。除了 TCP 协议,ActiveMQ 还支持 AMQP、STOMP、MQTT 等多种协议,可根据实际需求进行配置 。
这种模式的优点是实现相对简单,能够提供基本的高可用性保障,适合对集群复杂性要求不高、规模较小的应用场景,在一些小型企业的内部系统中,如果对消息服务的可靠性有一定要求,但又不想投入过多的资源进行复杂的集群配置,就可以采用这种模式 。然而,它也存在明显的缺点,由于只有一个 Master 和一个 Slave,扩展能力非常有限,难以满足大规模业务增长的需求;并且在 Master 失效后,若想恢复 Master,需要停止 Slave,拷贝 Slave 中的数据文件到 Master 中,然后重启,操作过程较为繁琐 。
在配置方面,Master 不需要做特殊配置。对于 Slave broker,在${ACTIVEMQ_HOME}/conf/activemq.xml文件的
masterConnectorURI="tcp://0.0.0.0:61616" shutdownOnMasterFailure="false" dataDirectory="${activemq.base}">
同时,需要修改 Slave 的服务端口,以避免与 Master 端口冲突,示例如下:
不过需要注意的是,从 ActiveMQ 5.8 版本开始,Pure Master Slave 模式已被废弃,不再推荐使用 。
2. Shared File System Master Slave:基于共享文件系统实现的 Master - Slave 模式,其原理是利用共享文件系统来存储消息数据。ActiveMQ 的默认数据库 kahaDB 底层是文件系统,多个 ActiveMQ 实例共享同一个文件存储目录。哪个 ActiveMQ 实例先获取共享文件的锁,那个实例就是 Master,其它的 ActiveMQ 实例就是 Slave。当当前的 Master 失效时,其它的 Slave 就会去竞争共享文件锁,谁竞争到了谁就是新的 Master 。
这种模式的优势在于 Slave 的个数没有限制,具有较好的扩展性;并且当 Master 失效时,无需手动配置,只要有足够多的 Slave,就可以自动选举出新的 Master,提高了系统的可用性 。在配置共享文件系统时,如果是在同一台机器上进行测试,可以将持久化适配器的存储目录改为本地磁盘的一个固定目录,多个实例共享这个目录,示例如下:
如果各个 ActiveMQ 实例需要运行在不同的机器上,就需要使用分布式文件系统,如 NFS(Network File System)、Ceph 等。在 broker 配置方面,除了上述持久化适配器的配置外,还需要修改每个 broker 实例的服务端口和 jetty 的服务端口,防止端口占用异常 。
3. JDBC Master Slave:该模式使用数据库作为持久化存储来实现主从模式。其原理与 Shared File System Master Slave 模式类似,多个 ActiveMQ 实例连接到同一个共享数据库,通过争抢数据库连接并锁定数据库操作权限来确定 Master 和 Slave。争抢到连接的称为 Master,其他 broker 称为 Slave 。如果当前 Master 挂掉,另外几个 Slave 会继续争抢,挂掉的 broker 重连成功后仍然作为 Slave 。
在配置时,首先需要在所有的 ActiveMQ 的主配置文件(${ACTIVEMQ_HOME}/conf/activemq.xml)中添加数据源,所有的数据源都指向同一个数据库。以 MySQL 为例,配置示例如下:
然后修改持久化适配器,使用jdbcPersistenceAdapter,示例如下:
这种方式的集群相对 Shared File System Master Slave 更加简单,更容易进行分布式部署。但是,如果数据库失效,那么所有的 ActiveMQ 实例都将失效,因此对数据库的可靠性要求较高 。在实际应用中,通常会结合数据库的主从复制、集群等技术来提高数据库的可靠性 。
在activemq.xml中配置static network Connector的示例如下:
在这个示例中,name属性为该网络连接器指定了一个名称,方便管理和识别;uri属性指定了要连接的远程 broker 的地址,这里通过static协议指定了两个远程 broker 的 TCP 地址和端口 。当一个 broker 接收到消息后,如果本地没有对应的消费者,它会根据配置的networkConnector将消息转发到其他 broker 上,由其他 broker 上的消费者进行处理 。
2. 动态 Broker - Cluster:动态 Broker - Cluster 基于组播动态发现 brokers。其原理是通过组播的形式,让各个 broker 自动发现彼此并建立连接。在这种模式下,broker 在启动时会通过组播地址发送和接收发现消息,从而动态地获取可连接的 broker 地址 。
在activemq.xml中,需要对transportConnectors和networkConnectors进行相关配置修改。例如:
...
在上述配置中,transportConnector的discoveryUri属性指定了组播地址为multicast://default,表示该 broker 将通过这个组播地址进行发现;networkConnector的uri属性也设置为multicast://default,表示通过组播来建立网络连接 。这样,各个 broker 就可以通过组播自动发现彼此并建立连接,实现动态的集群配置 。动态 Broker - Cluster 配置相对灵活,不需要手动硬编码每个 broker 的地址,适合在网络环境变化频繁或需要快速扩展集群的场景中使用 。然而,组播在一些网络环境中可能会受到限制,如防火墙的阻挡等,需要在部署时特别注意网络配置 。
在生产环境中,单一的 Master - Slave 模式虽然能解决单点故障问题,保证消息服务的可靠性,但无法实现负载均衡;而单一的 Broker - Cluster 模式虽能实现负载均衡和消息的分布式处理,但在节点故障时可能会出现消息丢失等问题,无法满足高可用性的严格要求 。因此,将 Master - Slave 模式与 Broker - Cluster 模式结合起来,能够充分发挥两者的优势,提供更可靠、高效的消息服务。
在这种组合配置中,首先搭建 Master - Slave 集群,确保消息的可靠存储和高可用性。通过共享文件系统或 JDBC 等方式实现主从节点之间的数据同步和故障转移 。然后,在 Master - Slave 集群的基础上,搭建 Broker - Cluster,实现消息的负载均衡和分布式处理 。各个 Master 和 Slave 节点通过networkConnector相互连接,形成一个更大的集群网络 。
具体的配置步骤如下:
这里假设已经搭建了两个 broker 节点,分别为broker1和broker2,通过static协议配置了它们之间的网络连接,duplex="true"表示启用双向连接,即两个 broker 之间可以相互发送和接收消息 。
3. 配置客户端连接。客户端使用failover协议连接到集群,例如:
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(tcp://broker1:61616,tcp://broker2:61617)?randomize=false&priorityBackup=true");
在这个示例中,failover协议表示当一个 broker 节点不可用时,客户端会自动切换到其他可用节点;randomize=false表示按列表顺序调用,不随机选择节点;priorityBackup=true表示当randomize为false时,优先选择第一个节点作为主节点 。
通过这种 Master - Slave + Broker - Cluster 的组合配置,既保证了消息服务的高可用性,又实现了负载均衡和分布式处理,能够满足生产环境中复杂、高并发的业务需求 。