AMQ 虚拟topic

本文介绍如何利用Apache ActiveMQ中的虚拟Topic机制解决多消费者重复消费的问题,并通过实例演示了普通Topic与虚拟Topic的区别。虚拟Topic能确保消息只被同一组内的一个消费者接收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

业务场景:

为了做到高可用性,topic的consumer服务通常是多台服务。如果用普通的Topic,则多个consumer的服务就会出现重复消费的情况。

解决方案:

AMQ引入了虚拟Topic,如果Topic的名字是以"VirtualTopic."开头,则AMQ自动将其识别为虚拟主题的Topic,如 VirtualTopic.NORMAL

      其对应的consumer则需要以 "Consumer.groupName.VirtualTopic.X"的格式命名,其中groupName是为了标记consumer的分组,如 Consumer.normal.VirtualTopic.NORMAL。

原理:

    AMQ是通过Queue来实现这个功能。

package com.hayden.amq;

import java.util.concurrent.atomic.AtomicInteger;

import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.junit.Test;
  
public class TestVirtualTopic {  
  
	@Test
    public void testNormalTopic() {  
        try {  
  
            ActiveMQConnectionFactory factoryA = getAMQConnectionFactory();  
  
            ActiveMQTopic queue = new ActiveMQTopic(getNormalTopicName());  
            ActiveMQConnection conn = (ActiveMQConnection) factoryA.createConnection();  
            conn.start();  
            Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);  
  
            MessageConsumer consumer1 = session.createConsumer( queue );  
            MessageConsumer consumer2 = session.createConsumer( queue );  
            final AtomicInteger aint1 = new AtomicInteger(0);  
            MessageListener listenerA = new MessageListener() {  
                public void onMessage(Message message) {  
                    try {  
                    	int index = aint1.incrementAndGet();
                        System.out.println(index
                                + " => receive from "+ getNormalTopicName() +": " + message);  
                        	Thread.sleep(10L);
                   
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            };  
            
            consumer1.setMessageListener(listenerA);  
            consumer2.setMessageListener(listenerA);  
           
            MessageProducer producer = session.createProducer(new ActiveMQTopic(getNormalTopicName()));  
            int index = 0;  
            while (index++ < 100) {  
//            	System.out.println("Start to send msg");
            	TextMessage message = session.createTextMessage(index  
                        + " message.");  
                producer.send(message); 
                Thread.sleep(5L);
            }  
  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }
	
	@Test
	 public void testNoralVirtualTopic() {  
	        try {  
	  
	            ActiveMQConnectionFactory factoryA = getAMQConnectionFactory();  
	  
	            Queue queue = new ActiveMQQueue(getVirtualTopicConsumerName());  
	            ActiveMQConnection conn = (ActiveMQConnection) factoryA.createConnection();  
	            conn.start();  
	            Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);  
	  
	            MessageConsumer consumer1 = session.createConsumer( queue );  
	            MessageConsumer consumer2 = session.createConsumer( queue );  
	       
	            final AtomicInteger aint1 = new AtomicInteger(0);  
	            MessageListener listenerA = new MessageListener() {  
	                public void onMessage(Message message) {  
	                    try {  
	                    	int index = aint1.incrementAndGet();
	                        System.out.println(index
	                                + " => receive from "+ getNormalVirtualTopicName() +": " + message);  
//	                        if(index % 2==0){
//	                        	this.wait(1000L);
//	                        }
	                    } catch (Exception e) {  
	                        e.printStackTrace();  
	                    }  
	                }  
	            };  
	            consumer1.setMessageListener(listenerA);  
	            consumer2.setMessageListener(listenerA);  
	            MessageProducer producer = session.createProducer(new ActiveMQTopic(getNormalVirtualTopicName()));  
	            int index = 0;  
	            while (index++ < 100) {  
	                TextMessage message = session.createTextMessage(index  
	                        + " message.");  
	                producer.send(message);  
	            }  
	  
	        } catch (Exception e) {  
	            e.printStackTrace();  
	        }  
	    }
	 
      @Test
    public void testVirtualTopic() {  
        try {  
  
            ActiveMQConnectionFactory factoryA = getAMQConnectionFactory();  
  
            Queue queue = new ActiveMQQueue(getVirtualTopicConsumerNameA());  
            ActiveMQConnection conn = (ActiveMQConnection) factoryA.createConnection();  
            conn.start();  
            Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);  
  
            MessageConsumer consumer1 = session.createConsumer( queue );  
            MessageConsumer consumer2 = session.createConsumer( queue );  
            MessageConsumer consumer3 = session.createConsumer( new ActiveMQQueue(getVirtualTopicConsumerNameB()) );  
            final AtomicInteger aint1 = new AtomicInteger(0);  
            MessageListener listenerA = new MessageListener() {  
                public void onMessage(Message message) {  
                    try {  
                        System.out.println(aint1.incrementAndGet()  
                                + " => receive from "+ getVirtualTopicConsumerNameA() +": " + message);  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            };  
            consumer1.setMessageListener(listenerA);  
            consumer2.setMessageListener(listenerA);  
            final AtomicInteger aint2 = new AtomicInteger(0);  
            MessageListener listenerB = new MessageListener() {  
                public void onMessage(Message message) {  
                    try {  
                        System.out.println(aint2.incrementAndGet()  
                                + " => receive from "+ getVirtualTopicConsumerNameB() +": " + message);  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            };  
            consumer3.setMessageListener(listenerB);  
              
            MessageProducer producer = session.createProducer(new ActiveMQTopic(getVirtualTopicName()));  
            int index = 0;  
            while (index++ < 10) {  
                TextMessage message = session.createTextMessage(index  
                        + " message.");  
                producer.send(message);  
            }  
  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }

	private ActiveMQConnectionFactory getAMQConnectionFactory() {
		return new ActiveMQConnectionFactory(  
		        "tcp://127.0.0.1:61616");
	}  
      
	  protected static String getNormalTopicName() {  
          return "nomal.TEST";  
      }  
	  
      protected static String getNormalVirtualTopicName() {  
          return "VirtualTopic.NORMAL";  
      }  
      
      protected static String getVirtualTopicName() {  
            return "VirtualTopic.TEST";  
        }  
      
      protected static String getVirtualTopicConsumerName() {  
          return "Consumer.normal.VirtualTopic.NORMAL";  
      }
  
        protected static String getVirtualTopicConsumerNameA() {  
            return "Consumer.A.VirtualTopic.TEST";  
        }  
          
        protected static String getVirtualTopicConsumerNameB() {  
            return "Consumer.B.VirtualTopic.TEST";  
        }  
  
}  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值