上一次我们聊了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的消息的分配策略默认是按照轮询的策略发送消息,即发送的顺序是消费者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
11
consumer_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