上一次我们聊了RabbitMQ服务的构建和简单使用。我在这里聊一下里面的关键字:

Message :消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、 priority(相对于其他消息的优先权)、 delivery-mode(指出 该消息可能需要持久性存储)等。

Publisher:消息的生产者,也是一个向交换器发布消息的客户端应用程序

Exchange:交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。Exchange有4种类型: direct(默认), fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别

Queue:消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。

Binding:绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连 
接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。Exchange 和Queue的绑定可以是多对多的关系。 
Connection:网络连接,比如一个TCP连接。 
Channel:信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内的虚拟连接, AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。 
Consumer:消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。 
Virtual Host:虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。 vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。

好了我们接着说多消费模式,关于多消费者模式和一对一消费模式看下面的图来大致的解释一下:

rabbitmq spring 创建多个消费者 rabbitmq direct 多个消费者_ide


 

一对一模式:一个消息的生产者对应一个消息的消费者。

一对多模式:一个消息的生产者对应多个消息的消费者。

一对一模式上一篇聊完了,今天看多消费模式:
注意:如果同一个队列,有多个消费者消费这个队列。RabbitMQ的消息的分配策略默认是按照轮询的策略发送消息,即发送的顺序是消费者1,消费者2,消费者1,消费者2…。所以平均下来,每个消费者消费的消息数量几乎相同。

provdier:

 

package com.alibaba.more;

import com.alibaba.ConnectUtil;
import com.alibaba.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * 多消费者模式消息的生产者
 */
public class Provider {

    private static final String QUEUE_NAME = "USER_MASSAGE";

    public  void massageProvider(){
        Connection connection = null;
        Channel channel = null;
        try{
            connection = ConnectUtil.getRabbitMqConnect();
            channel = connection.createChannel();

            //声明一个队列
            channel.queueDeclare(QUEUE_NAME,false,false,false,null);

            //创建用户的对象
            for (int i = 0 ; i < 20 ; i++){
                ObjectMapper objectMapper = new ObjectMapper();
                byte[] body = objectMapper.writeValueAsBytes(new User("用户" + i,"12345" + i));
                channel.basicPublish("",QUEUE_NAME,null,body);
                Thread.sleep(3000);
            }
        }catch (Exception e){
            System.out.println("Provider/massageProvider Exception:" + e.getMessage());
        }
    }

    public static void main(String[] args) {
        new Provider().massageProvider();
    }
}

consumer_1:

package com.alibaba.more;

import com.alibaba.ConnectUtil;
import com.alibaba.User;
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.*;

import java.io.IOException;

public class ConsumerOne {

    private static final String QUEUE_NAME = "USER_MASSAGE";

    @SuppressWarnings("all")
    public void getUserMassage(){
        Connection connection = null;
        Channel channel = null;
        try{
            connection = ConnectUtil.getRabbitMqConnect();
            channel = connection.createChannel();
            while (true){
                Consumer consumer = new DefaultConsumer(channel){
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                        System.out.println(consumerTag);
                        String str = new String(body, "UTF-8");
                        System.out.println("收到消息为:" + str);
                        User user = JSONObject.parseObject(str, User.class);
                        System.out.println(user.toString());

                        System.out.println(envelope.getDeliveryTag());
                    }
                };
                channel.basicConsume(QUEUE_NAME,true,consumer);

                Thread.sleep(1000);
            }
        }catch (Exception e){
            System.out.println("ConsumerOne/getUserMassage Exception:" + e.getMessage());
        }
    }

    public static void main(String[] args) {
        new ConsumerOne().getUserMassage();
    }
}
consumer_2:
package com.alibaba.more;

import com.alibaba.ConnectUtil;
import com.alibaba.User;
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.*;

import java.io.IOException;

public class ConsumerTwo {

    private static final String QUEUE_NAME = "USER_MASSAGE";

    @SuppressWarnings("all")
    public void getUserMassage(){
        Connection connection = null;
        Channel channel = null;
        try{
            connection = ConnectUtil.getRabbitMqConnect();
            channel = connection.createChannel();
            while (true){
                Consumer consumer = new DefaultConsumer(channel){
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                        System.out.println(consumerTag);
                        String str = new String(body,"UTF-8");
                        System.out.println("收到消息为:" + str);
                        User user = JSONObject.parseObject(str,User.class);
                        System.out.println(user.toString());

                        System.out.println(envelope.getDeliveryTag());
                    }
                };
                channel.basicConsume(QUEUE_NAME,true,consumer);
                Thread.sleep(1000);
            }
        }catch (Exception e){
            System.out.println("ConsumerTwo/getUserMassage Exception:" + e.getMessage());
        }
    }

    public static void main(String[] args) {
        new ConsumerTwo().getUserMassage();
    }
}

result:

consumer_1:

amq.ctag-WPuSih_isxNoQ5it4KEsJw
 收到消息为:{"username":"用户0","password":"123450"}
 用户名为:用户0-->密码为:123450
 1
 amq.ctag-VITJxolQXcfJu5c3xD3z-g
 收到消息为:{"username":"用户1","password":"123451"}
 用户名为:用户1-->密码为:123451
 2
 amq.ctag-7CiAYWQVO_9KcoGh41ojHA
 收到消息为:{"username":"用户2","password":"123452"}
 用户名为:用户2-->密码为:123452
 3
 amq.ctag-H_-L5EYseJ2Bt5htgw1uCA
 收到消息为:{"username":"用户4","password":"123454"}
 用户名为:用户4-->密码为:123454
 4
 amq.ctag-Hk_2hzlcxBOM4VugKbFFgQ
 收到消息为:{"username":"用户6","password":"123456"}
 用户名为:用户6-->密码为:123456
 5
 amq.ctag-Xe8uYhT6E4IUZjWoTHn0gw
 收到消息为:{"username":"用户8","password":"123458"}
 用户名为:用户8-->密码为:123458
 6
 amq.ctag-j3fMAOUkZJteFnrbVzzp_w
 收到消息为:{"username":"用户10","password":"1234510"}
 用户名为:用户10-->密码为:1234510
 7
 amq.ctag-om6qtVGceH4z-YTBuJfU6g
 收到消息为:{"username":"用户12","password":"1234512"}
 用户名为:用户12-->密码为:1234512
 8
 amq.ctag-oMzzP08s2mrt87DQrUKsjg
 收到消息为:{"username":"用户14","password":"1234514"}
 用户名为:用户14-->密码为:1234514
 9
 amq.ctag-ZqYivNaOir2oCLoL_3huHA
 收到消息为:{"username":"用户16","password":"1234516"}
 用户名为:用户16-->密码为:1234516
 10
 amq.ctag-lU_PHNm4GreQINe8e9ev-w
 收到消息为:{"username":"用户18","password":"1234518"}
 用户名为:用户18-->密码为:1234518
 11consumer_2:
amq.ctag-ausnzCYsdCFLazq90zC_Gg
 收到消息为:{"username":"用户3","password":"123453"}
 用户名为:用户3-->密码为:123453
 1
 amq.ctag-WdSHfmVOoIs2LfPLjRg-7A
 收到消息为:{"username":"用户5","password":"123455"}
 用户名为:用户5-->密码为:123455
 2
 amq.ctag-JgRZxTGVox_LvEeBDLGLjw
 收到消息为:{"username":"用户7","password":"123457"}
 用户名为:用户7-->密码为:123457
 3
 amq.ctag-KGDysSDy1O_14PaRGzM56w
 收到消息为:{"username":"用户9","password":"123459"}
 用户名为:用户9-->密码为:123459
 4
 amq.ctag-IjGgWG3sIOV40DTzpIWn-A
 收到消息为:{"username":"用户11","password":"1234511"}
 用户名为:用户11-->密码为:1234511
 5
 amq.ctag-lRcdJq4zFarZm3_dRVnAPQ
 收到消息为:{"username":"用户13","password":"1234513"}
 用户名为:用户13-->密码为:1234513
 6
 amq.ctag-bawfdECQsvhUs_imKaDzNg
 收到消息为:{"username":"用户15","password":"1234515"}
 用户名为:用户15-->密码为:1234515
 7
 amq.ctag-BlFHmzxtimL3E7r5UPRfsg
 收到消息为:{"username":"用户17","password":"1234517"}
 用户名为:用户17-->密码为:1234517
 8
 amq.ctag-OuP8lpmE7iha8cjtgMswBQ
 收到消息为:{"username":"用户19","password":"1234519"}
 用户名为:用户19-->密码为:1234519
 9

多消费者模式在日常的研发中是很常用的,它最大的好处就是削峰平摊。但RabbitMQ相对于Kafka来讲还是稍微逊色一点的,尤其是在高吞吐量的消息并发时,KafKa的性能和表现优于RabbitMQ