ActiveMQ Classic 集群搭建

198 阅读9分钟

ActiveMQ 集群方案及搭建

ActiveMQ 分为 ActiveMQ Classic 版本和 新架构版本 ActiveMQ Artemis

目前公司内使用的是 ActiveMQ Classic 版本 , 版本号:5.15.16

  1. ActiveMQ Classic 集群

总体上 ActiveMQ Classic 集群 分为以下3大类

  • Networks of Brokers: 这是 ActiveMQ Classic 实现集群的主要方式

    • 官方链接: activemq.apache.org/components/…
    • 特点:broker之间相互连接组成星型网络,client端连接任意一个broker, 消息会在broker之间进行转发
  • MasterSlave: 用于实现高可用性,一个 Broker 作为 Master,其他作为 Slave。

  • Networks of Brokers + MasterSlave: 多个master-slaves组成一个集成网络,是上面两种方式的组合

通过下面表格中各种模式的对比,可以看到选择 Networks of Brokers 是一种轻量级的集群方案,保证了高性能的同时,在能及时 重启 broker宕机的情况下也能及时处理消息,因此选择此种模式作为集群方案

方式工作方式运维成本特点
Networks of BrokersBroker之间组成星型网络,所有broker均可处理请求,但如果有任意一个broker宕机,在宕机期间,此broker上存储的消息不能转发以及被消费,对此部分消息的消费有影响正常高性能(属于水平扩展)-理论上(需要压测)所有节点均可处理请求,但宕机节点消息无法被消费
MasterSlave只有成为master的broker能处理请求,slave broker平时不处理请求。解决了broker宕机消息无法被消费的场景正常高可用 - 1主多从模式保证了消息能被及时消费,但还是单节点处理请求
Networks of Brokers + MasterSlave上面两种方式的组合复杂高性能高可用
  1. ActiveMQ Classic - Networks of Brokers 集群方式搭建

本部署将构建一个 3 个 ActiveMQ 5.15.16 节点的 Network of Brokers 集群。每个节点独立运行,拥有自己的 KahaDB 存储。节点之间通过配置的网络连接互相感知和转发消息。客户端使用 Failover Transport 连接到集群中的一个或多个节点,从而实现自动故障转移和负载均衡。

软件版本:

JDK: openjdk8 adoptium.net/zh-CN/temur…

ActiveMQ: 5.15.16 activemq.apache.org/components/…

OS: 3台 centos7 (192.168.16.131,192.168.16.132,192.168.16.133)

  • 节点 IP 地址:

    • 节点 1: 192.168.16.131
    • 节点 2: 192.168.16.132
    • 节点 3: 192.168.16.133
  • 消息存储: KahaDB (文件存储,每个节点独立)

  • 集群模式: Network of Brokers (静态配置)

  • 操作系统 : CentOS 7

生产环境考虑:

  • 高可用性 : 客户端连接到 Network of Brokers 中的多个节点,当某个节点宕机时,客户端会自动连接到其他可用节点。
  • 持久化: 使用 KahaDB 确保消息和订阅在 broker 重启后不丢失。
  • 性能: 合理配置 KahaDB 参数、内存以及网络连接。
  • 安全性: 配置管理界面和传输连接的认证授权。
  • 可管理性: 使用 systemd 管理 ActiveMQ 服务,配置日志和监控。

部署步骤:

以下步骤需要在三台服务器 (192.168.16.131, 192.168.16.132, 192.168.16.133) 上重复执行,并根据具体节点信息进行相应的配置修改。

  1. 前置条件准备

  1. 安装 Java Development Kit (JDK): ActiveMQ 5.15.16 需要 Java 8 或更高版本。建议安装 OpenJDK 8。
  2. 创建 ActiveMQ 用户和组: 为了安全起见,不建议使用 root 用户运行 ActiveMQ。
sudo groupadd activemq
sudo useradd -r -g activemq -s /sbin/nologin activemq

3. 创建安装目录:

sudo mkdir -p /opt/activemq
sudo chown activemq:activemq /opt/activemq

4. 配置防火墙: 打开 ActiveMQ 相关的端口 (例如:OpenWire 61616, AMQP 5672, STOMP 61613, MQTT 1883, Web Console 8161)。您需要根据实际使用的协议开放端口。对于 Network of Brokers,还需要确保节点之间用于网络连接的端口是开放的 (默认通常是 transportConnector 的端口)。

sudo firewall-cmd --zone=public --add-port=61616/tcp --permanent
sudo firewall-cmd --zone=public --add-port=8161/tcp --permanent
# 根据需要开放其他协议端口# sudo firewall-cmd --zone=public --add-port=5672/tcp --permanent# sudo firewall-cmd --zone=public --add-port=61613/tcp --permanent# sudo firewall-cmd --zone=public --add-port=1883/tcp --permanent
sudo firewall-cmd --reload

5. 调整系统参数 (可选,但推荐用于生产环境): 增加文件描述符限制。 6. 编辑 /etc/security/limits.conf 文件,在文件末尾添加以下行:

activemq - nofile 65536    ##限制用户最大文件打开数量
activemq - nproc 16384     ##限制用户打开的最大进程数量

7. 编辑 /etc/sysctl.conf 文件,添加或修改以下行:

vm.swappiness = 10 # 减少 swap 使用
net.core.somaxconn = 4096 # 增加 listen 队列长度
net.ipv4.tcp_tw_reuse = 1 # 允许重用 TIME-WAIT 状态的 socket
net.ipv4.tcp_fin_timeout = 30 # 减少 FIN-WAIT-2 状态的超时时间
  1. 执行 sudo sysctl -p 使配置生效。
  1. 下载和安装 Active MQ

  1. 下载 ActiveMQ 5.15.16
  2. 解压安装包:
sudo tar -zxvf apache-activemq-5.15.16-bin.tar.gz -C /opt/activemq --strip-components=1

3. 现在 ActiveMQ 文件应该在 /opt/activemq 目录下。 4. 设置文件权限:

sudo chown -R activemq:activemq /opt/activemq

3. #### 配置 ActiveMQ 集群 (Network of Brokers)

编辑每个节点上的 /opt/activemq/conf/activemq.xml 文件。以下是一个基础的配置示例,您需要根据实际情况修改 <broker> 标签中的 brokerName 以及 <networkConnectors> 部分。

重要提示:

  • 每个节点的 brokerName 必须唯一
  • <networkConnectors> 部分需要列出集群中所有其他节点的传输连接地址。

以下是 安装目录下 conf/activemq.xml 配置,主要修改 broker 以及networkConnectors 中相关配置

<!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->
<!-- START SNIPPET: example -->
<beans
  xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">

    <!-- Allows us to use system properties as variables in this configuration file -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <value>file:${activemq.conf}/credentials.properties</value>
        </property>
    </bean>

   <!-- Allows accessing the server log -->
    <bean id="logQuery" class="io.fabric8.insight.log.log4j.Log4jLogQuery"
          lazy-init="false" scope="singleton"
          init-method="start" destroy-method="stop">
    </bean>

    <!--
        The <broker> element is used to configure the ActiveMQ broker.
    -->
    <broker xmlns="http://activemq.apache.org/schema/core" brokerName="borker1-192.168.16.131" dataDirectory="${activemq.data}" start="true" persistent="true">

        <destinationPolicy>
            <policyMap>
              <policyEntries>
                <policyEntry topic=">" >
                    <!-- The constantPendingMessageLimitStrategy is used to prevent
                         slow topic consumers to block producers and affect other consumers
                         by limiting the number of messages that are retained
                         For more information, see:

                         http://activemq.apache.org/slow-consumer-handling.html

                    -->
                  <pendingMessageLimitStrategy>
                    <constantPendingMessageLimitStrategy limit="1000"/>
                  </pendingMessageLimitStrategy>
                </policyEntry>
              </policyEntries>
            </policyMap>
        </destinationPolicy>


        <!--
            The managementContext is used to configure how ActiveMQ is exposed in
            JMX. By default, ActiveMQ uses the MBean server that is started by
            the JVM. For more information, see:

            http://activemq.apache.org/jmx.html
        -->
        <managementContext>
            <managementContext createConnector="false"/>
        </managementContext>

        <!--
            Configure message persistence for the broker. The default persistence
            mechanism is the KahaDB store (identified by the kahaDB tag).
            For more information, see:

            http://activemq.apache.org/persistence.html
        -->
        <persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
        </persistenceAdapter>
        
        <networkConnectors>
        <networkConnector uri="static:(tcp://192.168.16.132:61616)"
                          name="connector-to-node2"
                          conduitSubscriptions="true"
                          prefetchSize="1"
                          networkTTL="2"/>
        <networkConnector uri="static:(tcp://192.168.16.133:61616)"
                          name="connector-to-node3"
                          conduitSubscriptions="true"
                          prefetchSize="1"
                          networkTTL="2"/>
        </networkConnectors>


          <!--
            The systemUsage controls the maximum amount of space the broker will
            use before disabling caching and/or slowing down producers. For more information, see:
            http://activemq.apache.org/producer-flow-control.html
          -->
          <systemUsage>
            <systemUsage>
                <memoryUsage>
                    <memoryUsage percentOfJvmHeap="70" />
                </memoryUsage>
                <storeUsage>
                    <storeUsage limit="100 gb"/>
                </storeUsage>
                <tempUsage>
                    <tempUsage limit="50 gb"/>
                </tempUsage>
            </systemUsage>
        </systemUsage>

        <!--
            The transport connectors expose ActiveMQ over a given protocol to
            clients and other brokers. For more information, see:

            http://activemq.apache.org/configuring-transports.html
        -->
        <transportConnectors>
            <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
            <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        </transportConnectors>

        <!-- destroy the spring context on shutdown to stop jetty -->
        <shutdownHooks>
            <bean xmlns="http://www.springframework.org/schema/beans" class="org.apache.activemq.hooks.SpringContextHook" />
        </shutdownHooks>

    </broker>

    <!--
        Enable web consoles, REST and Ajax APIs and demos
        The web consoles requires by default login, you can disable this in the jetty.xml file

        Take a look at ${ACTIVEMQ_HOME}/conf/jetty.xml for more details
    -->
    <import resource="jetty.xml"/>

</beans>

节点配置修改说明:

  • 节点 1 (192.168.16.131):

    • <broker brokerName="broker-node1" ...>
    • <networkConnector uri="static:(tcp://192.168.16.132:61616)" ... name="connector-to-node2"/>
    • <networkConnector uri="static:(tcp://192.168.16.133:61616)" ... name="connector-to-node3"/>
  • 节点 2 (192.168.16.132):

    • <broker brokerName="broker-node2" ...>
    • <networkConnector uri="static:(tcp://192.168.16.131:61616)" ... name="connector-to-node1"/>
    • <networkConnector uri="static:(tcp://1968.16.133:61616)" ... name="connector-to-node3"/>
  • 节点 3 (192.168.16.133):

    • <broker brokerName="broker-node3" ...>
    • <networkConnector uri="static:(tcp://192.168.16.131:61616)" ... name="connector-to-node1"/>
    • <networkConnector uri="static:(tcp://192.168.16.132:61616)" ... name="connector-to-node2"/>

其他重要 配置项 说明:

  • persistent="true": 确保消息持久化。

  • <kahaDB directory="${activemq.data}/kahadb"/>: 配置 KahaDB 存储路径。${activemq.data} 变量通常指向 /opt/activemq/data 目录。

  • <networkConnectors>:

    • uri="static:(...)": 使用静态方式配置要连接的其他 broker 地址。
    • conduitSubscriptions="true": 重要的配置,允许在 broker 之间转发订阅信息,使得消费者无论连接到哪个 broker 都能接收到发送到主题的消息。
    • prefetchSize="1": 建议在 Network of Brokers 中设置较小的 prefetchSize,以避免一个 broker 接收过多本应由其他 broker 处理的消息。
    • decreasingPriorities="true": 允许具有更高优先级的消息在网络连接上传输。
    • networkTTL="2": 消息在网络中转发的最大跳数,根据您的网络拓扑调整。
  • <transportConnectors>: 配置客户端连接 ActiveMQ 的方式和端口。tcp://0.0.0.0:61616 表示监听所有网络接口的 61616 端口。

  • <jetty>: 配置内置的 Jetty 服务器,用于托管 Web Console。修改 port 参数可以改变 Web Console 的访问端口。

  • 安全配置: 生产环境务必修改默认的用户名和密码 (admin/password),并根据您的需求配置更严格的认证授权规则。

  • 内存 和存储限制: 根据您的服务器资源和消息量调整 <systemUsage> 中的内存和存储限制,防止 broker 因资源耗尽而崩溃。

  1. 创建 Systemd 服务

在三台服务器上创建 ActiveMQ 的 systemd service unit 文件,以便于管理。创建文件 /etc/systemd/system/activemq.service:

[Unit]
Description=Apache ActiveMQ
After=network.target

[Service]
Type=forking
User=activemq
Group=activemq
WorkingDirectory=/opt/activemq
ExecStart=/opt/activemq/apache-activemq-5.15.16/bin/activemq start
ExecStop=/opt/activemq/apache-activemq-5.15.16/bin/activemq stop
Restart=on-failure

[Install]
WantedBy=multi-user.target

重新加载 systemd 配置并设置开机自启动:

sudo systemctl daemon-reload
sudo systemctl enable activemq

5. #### 启动 ActiveMQ 服务

在三台服务器上依次启动 ActiveMQ 服务:

sudo systemctl start activemq

检查服务状态和日志:

sudo systemctl status activemq
tail -f /opt/activemq/data/activemq.log # 查看详细日志

确认三个节点都成功启动并且在日志中可以看到它们互相连接的信息。

启动之后可以看到每个broker都是和其余两个broker建立了连接

  1. 客户端连接配置

客户端连接 ActiveMQ 集群时,应该使用 Failover Transport,并列出集群中所有节点的地址。这样当一个节点不可用时,客户端会自动尝试连接其他节点。

例如,Java 客户端的连接 URL 如下:

failover:(tcp://192.168.16.131:61616,tcp://192.168.16.132:61616,tcp://192.168.16.133:61616)?initialReconnectDelay=100&maxReconnectAttempts=10

7. #### 生产环境最佳实践和监控

  1. 安全性强化:

    1. 修改默认的 Jolokia (JMX over HTTP) 配置,限制访问或禁用。
    2. 配置 SSL/TLS 来加密客户端和 broker 之间的通信,以及 broker 之间的网络连接。
    3. 使用更复杂的认证授权配置,例如 LDAP。
  2. 监控:

    1. 配置 JMX 监控,可以使用 JConsole, VisualVM 或 Prometheus + JMX Exporter 等工具来监控 broker 的关键指标 (队列深度、消息速率、连接数、内存使用等)。
    2. 监控系统日志和 ActiveMQ 日志文件。
    3. 设置告警规则。
  3. 日志管理:

    1. 配置日志滚动和归档,避免日志文件过大。
    2. 将日志发送到集中的日志管理系统 (如 ELK Stack)。
  4. 资源管理:

    1. 根据实际负载调整 <systemUsage> 中的内存和存储限制。
    2. 监控服务器的 CPU、内存、磁盘 I/O 和网络使用情况。
  5. 备份: 虽然 Network of Brokers 中每个节点有自己的存储,但定期备份每个节点的 KahaDB 目录仍然是推荐的做法,以防发生不可恢复的数据损坏。

  6. 网络稳定性: 确保 broker 之间的网络连接稳定可靠,低延迟,高带宽。网络问题是 Network of Brokers 集群中最常见的故障原因之一。

  7. 理解消息路由: 在 Network of Brokers 中,消息路由取决于消费者在哪里连接。默认情况下,消息会被路由到网络中连接了相应消费者的 broker。理解消息路由机制有助于排查问题和优化性能。

  8. 版本更新和漏洞: ActiveMQ 5.15.16 是一个较旧的版本,虽然您指定了这个版本,但请注意关注 ActiveMQ 社区发布的任何安全公告和更新。例如,针对 OpenWire 协议曾有严重的安全漏洞 (CVE-2023-46604),尽管 5.15.16 修复了此特定漏洞,但升级到更新版本通常能获得更多安全修复和改进。