消息中间件 - ActiveMQ高级特性和用法-消费者集群下需要考虑的问题(十一)

我们现实中往往有这样的需求:

1. 消息接收方和发送方都是集群。 

2. 同一个消息的接收方可能有多个集群进行消息的处理。

3. 不同集群对于同一条消息的处理不能相互干扰。

希望可以达到如下的效果:

对于集群消息,采用单独采用queue或者topic都不满足要求。

采用Queue模型导致:单独的queue,消息可能被其他集群消费

采用Topic模型导致,采用topic消息可能被同一集群的相同应用重复消费。

解决方案一,级联

将Jms的Topic和Queue进行级联使用

缺点,实现方式繁重,需要独立的中转的消息订阅者来完成,多了一次消息的投递和一次消息消费过程,对效率有影响,增加了消息中间件负载压力。

解决方案二

ActiveMQ提供了虚拟主题和组合Destinations都可以达到这个效果。

虚拟Destination

对于消息发布者来说,就是一个正常的Topic,名称以VirtualTopic.开头。例如VirtualTopic.vtgroup

对于消息接收端来说,是个队列,不同应用里使用不同的前缀作为队列的名称,即可表明自己的身份即可实现消费端应用分组。

  例如Consumer.A.VirtualTopic. vtgroup,说明它是名称为A群组的消费端,同理Consumer.B.VirtualTopic. vtgroup说明是一个名称为B群组的客户端。

默认虚拟主题的前缀是 :VirtualTopic.

 消费虚拟地址默认格式:Consumer.*.VirtualTopic.

生产者

public class VtProducer {

    //默认连接用户名
    private static final String USERNAME
            = ActiveMQConnection.DEFAULT_USER;
    //默认连接密码
    private static final String PASSWORD
            = ActiveMQConnection.DEFAULT_PASSWORD;
    //默认连接地址
    private static final String BROKEURL
            = ActiveMQConnection.DEFAULT_BROKER_URL;
    //发送的消息数量
    private static final int SENDNUM = 10;

    public static void main(String[] args) {
        ConnectionFactory connectionFactory;
        Connection connection = null;
        Session session;
        Destination destination;
        MessageProducer messageProducer;

        connectionFactory
                = new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKEURL);

        try {
            connection = connectionFactory.createConnection();
            connection.start();

            session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);
            destination = session.createTopic("VirtualTopic.vtgroup");
            messageProducer = session.createProducer(destination);
            for(int i=0;i<SENDNUM;i++){
                String msg = "vtgroup "+i+" "+System.currentTimeMillis();
                TextMessage message = session.createTextMessage(msg);
                System.out.println("发送消息:"+msg);
                messageProducer.send(message);
            }
            session.commit();


        } catch (JMSException e) {
            e.printStackTrace();
        }finally {
            if(connection!=null){
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }


    }


}

消费者A

public class VtConsumerA {

    private static final String USERNAME
            = ActiveMQConnection.DEFAULT_USER;//默认连接用户名
    private static final String PASSWORD
            = ActiveMQConnection.DEFAULT_PASSWORD;//默认连接密码
    private static final String BROKEURL
            = ActiveMQConnection.DEFAULT_BROKER_URL;//默认连接地址

    public static void main(String[] args) {
        ConnectionFactory connectionFactory;//连接工厂
        Connection connection = null;//连接

        Session session;//会话 接受或者发送消息的线程
        Destination destination;//消息的目的地

        MessageConsumer messageConsumer;//消息的消费者

        //实例化连接工厂
        connectionFactory = new ActiveMQConnectionFactory(VtConsumerA.USERNAME,
                VtConsumerA.PASSWORD, VtConsumerA.BROKEURL);

        try {
            //通过连接工厂获取连接
            connection = connectionFactory.createConnection();
            //启动连接
            connection.start();
            //创建session
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建一个消息队列
            destination = session.createQueue("Consumer.A.VirtualTopic.vtgroup");

            //创建消息消费者
            messageConsumer = session.createConsumer(destination);
            messageConsumer.setMessageListener(new MessageListener() {
                public void onMessage(Message message) {
                    try {
                        System.out.println("Accept msg : "
                                +((TextMessage)message).getText());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });


        } catch (JMSException e) {
            e.printStackTrace();
        }

    }
}

消费A2:

            //创建session
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建一个消息队列
            destination = session.createQueue("Consumer.A.VirtualTopic.vtgroup");

            //创建消息消费者
            messageConsumer = session.createConsumer(destination);

消费B:

            //创建session
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建一个消息队列
            destination = session.createQueue("Consumer.B.VirtualTopic.vtgroup");

            //创建消息消费者
            messageConsumer = session.createConsumer(destination);

 

消费C:

            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建一个消息队列
            destination = session.createQueue("Consumer.C.VirtualTopic.vtgroup");

            //创建消息消费者
            messageConsumer = session.createConsumer(destination);

组合Destination

组合队列允许用一个虚拟的destination代表多个destinations。这样就可以通过composite destinations在一个操作中同时向多个destination发送消息。

多个destination之间采用“,”分割。例如:

  Queue queue = new ActiveMQQueue("FOO.A,FOO.B,FOO.C");

  或

  Destination destination = session.createQueue("my-queue,my-queue2");

如果希望使用不同类型的destination,那么需要加上前缀如queue:// 或topic://,例如:

    Queue queue = new ActiveMQQueue("cd.queue,topic://cd.mark");

生产者:

            session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);
            destination = session.createQueue("cd.queue,topic://cd.mark,otherqueue");
            messageProducer = session.createProducer(destination);

消费者otherqueue:

            //创建session
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建一个连接HelloWorld的消息队列
            destination = session.createQueue("otherqueue");

            //创建消息消费者
            messageConsumer = session.createConsumer(destination);

消费者queueA:

            //创建session
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建一个连接HelloWorld的消息队列
            destination = session.createQueue("cd.queue");

            //创建消息消费者
            messageConsumer = session.createConsumer(destination);

消费者queueB:

            //创建session
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建一个连接HelloWorld的消息队列
            destination = session.createQueue("cd.queue");

            //创建消息消费者
            messageConsumer = session.createConsumer(destination);

消费者topic

            //创建session
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建一个连接HelloWorld的消息队列
            destination = session.createTopic("cd.mark");

            //创建消息消费者
            messageConsumer = session.createConsumer(destination);

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值