ActiveMQ静态网络集群

Networks of brokers

一、说明

是指多个broker组成集群,当其中一个broker的消费者出问题导致消息堆积无法消费掉时,通过ActiveMQ支持的Network of Broker方案可将该broker堆积的消息转发到其他有消费者的broker

ActiveMQ集群有好几种模式,其中网络集群模式分为静态网络和动态网络;本文主要介绍ActiveMQ的静态网络集群模式;

1、静态网络:就是在Broker集群配置中配置static的网络地址,以供服务启动的时候建立网络集群

静态网络的实现,主要是基于networkConnector元素配置完成

2、动态网络:是通过配置发现地址,在服务启动后还可以动态的增加节点,比较适用于动态扩容需求的场景;主要是基于transportConnector元素配置完成

二、集群搭建

ActiveMQ的networkConnector默认是单向的,一个Broker在一端发送消息,另一个Broker在另一端接收消息,这就是所谓的"桥接"。ActiveMQ也支持双向链接,创建一个双向的通道对于两个Broker不仅发送消息而且也能从相同的通道接收消息,通常作为duplex connector来映射

一般推荐的静态网络应用架构如下:

架构图片

以下根据笔者环境进行一个静态网络集群的搭建;

(应为硬件资源限制,笔者直接在单台机器搭建一个集群)

1. 目录规划

/opt/server

broker1、broker2、broker3

2. 服务器及端口规划:

序号

服务名称

服务器IP

服务端口

监控端口

1

broker1

10.10.1.44

61616

5762

1883

8161

2

broker2

10.10.1.44

61617

5763

1884

8162

3

broker3

10.10.1.44

61618

5764

1885

8163

为了便于记忆,我在本地做了host映射,server1.com ,后在访问服务器或是控制台可以直接用http://server1.com:8161访问

3. 服务器参数配置

以上三个节点需要在每个节点的 conf/activemq.xml中添加静态网络配置的参数,如下


<networkConnectors>

    <networkConnector name="bridge" uri="static://(tcp://localhost:61616,tcp://localhost:61617,tcp://localhost:61618)" dynamicOnly="false" duplex="true" />

</networkConnectors>

1.name: 默认的bridge

2.dynamicOnly: 默认是false,如果为true,持久订阅被激活时才创建对应的网络持久订阅。默认是启动时激活

3.decreaseNetworkConsumerPriority: 默认是false。设定消费者优先权,如果为true,网络的消费者优先级降低为-5。如果为false,则默认跟本地消费者一样为0

4.networkTTL: 默认是1,网络中用于消息和订阅消费的broker数量

5.messageTTL: 默认是1,网络中用于消息的broker数量

6.consumerTTL: 默认是1,网络中用于消费的broker数量

7.conduitSubscriptions: 默认true,是否把同一个broker的多个consumer当做一个来处理(在做集群的时候如果有多个consumer,需要设置为false)

8.dynamicallyIncludedDestinations:默认为空,要包括的动态消息地址,类适于excludedDestinations; 以下主要是参照示例

networkConnector配置的可用属性

Broker1

Broker2

Broker2配置图例

Broker3

Broker3配置图例

完成以上配置然后重启各个Broker

验证是否配置成功

直接打开MQ的WEB控制台,默认地址 http://10.10.1.44:8161/ 到network的菜单项可以看到如下效果

然后到另外两个控制台查看是否也有如下配置,如果都有显示说明已经配置好,如果没有说明哪里配置的有问题,请参照上面步骤检查。

 

4. 消息验证

4.1、生产者客户端发送消息到Broker1,Consumer客户端从Broker3或Broker2上面订阅消息

示例代码: Producer

public class MQProducer {
   public static void main(String[] args) throws JMSException {
      // 连接到ActiveMQ服务器
      ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://server1.com:61616");
      Connection connection = factory.createConnection();
      connection.start();
      Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
      // 创建主题
      Topic topic = session.createTopic("VirtualTopic.TEST");
      MessageProducer producer = session.createProducer(topic);
      //  NON_PERSISTENT 非持久化 PERSISTENT 持久化,发送消息时用使用持久模式
      producer.setDeliveryMode(DeliveryMode.PERSISTENT);
      TextMessage message = session.createTextMessage();
      for (int i = 0; i < 4; i++) {
         message.setText("topic 消息。"+i);
         message.setStringProperty("property", "消息Property");
         //  发布主题消息
         producer.send(message);
      }
      System.out.println("消息发送完毕!");
      session.close();
      connection.close();
   }

}

示例代码:Consume

public class MQConsumer {
   public static void main(String[] args) throws JMSException {
      // 连接到ActiveMQ服务器
      ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://server1.com:61618");
      Connection connection = factory.createConnection();
      connection.start();
      Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
      // 创建主题
      Queue topicA = session.createQueue("Consumer.A.VirtualTopic.TEST");
      Queue topicB = session.createQueue("Consumer.B.VirtualTopic.TEST");
      // 创建消费者A组1-3号订阅
      String port = "61618-";
      createConsumerQueue(port + "A1", topicA, session);
//    createConsumerQueue(port + "A2", topicA, session);
      // createConsumerQueue("A3", topicA, session);
      // 创建消费者B组1-3号订阅
      // createConsumerQueue("B1", topicB, session);
      // createConsumerQueue("B2", topicB, session);
      // createConsumerQueue("B3", topicB, session);
   }

   private static void createConsumerQueue(String name, Queue topic, Session session) throws JMSException {
      // 创建消费者A组订阅
      MessageConsumer consumerA1 = session.createConsumer(topic);
      consumerA1.setMessageListener(new MessageListener() {
         @Override
         public void onMessage(Message msg) {
            try {
               System.out.println(msg.getJMSType());
               if (msg instanceof TextMessage) {
                  TextMessage tm = (TextMessage) msg;
                  System.out.println("Received message " + name + ": " + tm.getText() + ":"
                        + tm.getStringProperty("property"));

               } else if (msg instanceof ActiveMQBytesMessage) {
                  ActiveMQBytesMessage bytesMessage = (ActiveMQBytesMessage) msg;
                  if (bytesMessage != null) {
                     byte[] bt = new byte[(int) bytesMessage.getBodyLength()];
                     bytesMessage.readBytes(bt);
                     System.out.println("Received message " + name + ": " +new String(bt));
                  }
               }
            } catch (JMSException e1) {
               e1.printStackTrace();
            }
         }
      });
   }
}

以上,先运行Consumer 61618 和61617,再运行Producer;可以看到消息被两个客户端均匀消费

61617

61618

通过以上可以发现,集群搭建已经生效

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章