RabbitMQ常用名词
名词 | 介绍 |
交换机(Exchange) | 用来接收生产者发送的消息 把消息路由给服务器中的队列 |
Fanout | 广播:不管你是谁,我都把消息发给你 |
Direct | 发布与订阅 完全匹配:只要消费者的key和消息的key相同 那么就把消息发送给消费者 |
Topic | 主题,规则匹配:在direct的基础上增加了模糊匹配 (#,“ * ”) #代表0个词,一个词或者是多个词,“ * ”代表一个词 |
生产者(Pubilsher) | 消息的生产者,向交换机发布消息的客户端应用程序 |
消费者(Consumer) | 从消息队列中获取消息的客户端应用程序 |
绑定(Binding) | 用于绑定交换机和消息队列 一个绑定就是基于路由键将交换机和消息队列连接起来的路由规则 |
消息队列(Queue) | 用于保存消费者的消息,它是消息的容器,也是消息的终点。一个消息可以发送一个或者多个消息队列,消息会一直存放在消息队列中,直到被消费者取出 ,我们也可以使用过期时间来设定消息的存活时间 |
路由键(Routing-key) | RabbitMQ决定消息应该投递到哪一个消息队列的规则,队列是通过路由键绑定到的交换机。消息发送到MQ服务器时,消息将拥有一个路由键,即便是空 ,也会将其绑定的路由键进行匹配 。如果匹配成功,消息会投递到消息队列中,如果匹配失败。那么消息会进入黑洞(消失) |
连接(Connection) | rabbit服务器与服务建立的TCP连接 |
信道(channel) | 1.TCP中的虚拟连接(TCP相当于电缆,信道相当于一个独立的光纤,一个TCP上可以创建多条信道)2.TCP一旦打开就会创建AMQP信道。3.无论是发布消息,接收消息,订阅队列,这些动作都是通过信道完成的 |
AMQP | 一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。 |
虚拟主机(Virtual) | 虚拟主机是共享相同的身份认证和加密环境的独立服务器域 。每一个vhost相当于一个迷你版的RabbitMQ服务器,拥有自己的交换机,消息队列,绑定和权限机制。vhost是AMQP概念的基础,必须在连接时指定,RabbitMQ默认的vhost是/ |
Borker | 表示消息队列服务器实体 |
交换器和队列的关系 | 交换器是通过路由和队列绑定在一起,如果消息拥有的路由键与队列和交换机的路由键匹配,那么消息就会被路由到绑定的消息队列中,也就是说 消息到消息队列的过程中会先经过交换机,交换机通过路由键匹配分发消息到具体的消息队列中 |
MQ为什么要使用信道而不是直接使用TCP | 因为TCP的创建和销毁开销特别大,创建需要进行3次握手,销毁需要进行4次分手。如果不使用信道,那么在消息高峰期的时候每秒成千上万条的连接会造成大量的性能损耗,对资源造成大量的浪费,并且操作系统每秒处理的TCP连接数也是有限制的,必然会造成性能的瓶颈轮训分发 |
轮训分发 | 一个消费者一条 按均分配。 |
公平分发 | 会根据消费者的消费能力进行公平分发,处理快的就多消费,处理慢的就少消费(按劳分配) |
创建交换机 队列和绑定交换机与队列的两种方式
通过配置类的方式创建,绑定交换机和队列
在消费者中创建配置类
@Configuration
public class Direct {
//1.声明交换机
@Bean
public DirectExchange directExchange(){
//构造一个新的交换器,给定名称、持久性标志、自动删除标志。
return new DirectExchange("direct_order_exchange",true,false);
}
//2.声明队列
@Bean
public Queue smsQueue(){
//构造一个新的队列,给定一个名称和持久性标志。该队列是非独占的和非自动删除的。
return new Queue("sms.direct.queue",true);
}
@Bean
public Queue emailQueue(){
//构造一个新的队列,给定一个名称和持久性标志。该队列是非独占的和非自动删除的。
return new Queue("email.direct.queue",true);
}
@Bean
public Queue duanxinQueue(){
//构造一个新的队列,给定一个名称和持久性标志。该队列是非独占的和非自动删除的。
return new Queue("duanxin.direct.queue",true);
}
//3.绑定
@Bean
public Binding smsBinding(){
return BindingBuilder.bind(smsQueue()).to(directExchange()).with("sms");
}
@Bean
public Binding emailBinding(){
return BindingBuilder.bind(emailQueue()).to(directExchange()).with("email");
}
@Bean
public Binding duanxinBinding(){
return BindingBuilder.bind(duanxinQueue()).to(directExchange()).with("duanxin");
}
}
通过注解的方式创建,绑定交换机和队列
在消费者中创建
@Service
//交换机和路由的绑定关系
@RabbitListener(bindings = @QueueBinding(
//队列
value = @Queue(value = "duanxin.topic.queue",durable = "true",autoDelete = "false"),
//交换机
exchange = @Exchange(value = "topic_order_exchange",type = ExchangeTypes.TOPIC),
//路由
key = "duanxin.#"
))
public class TopicDuanxinConsumers {
@RabbitHandler
public void reviceMessages(String messages){
System.out.println("duanxin topic==>接收到订单的消息是:-》"+messages);
}
}
这里解释以下**@RabbitListener注解和@RabbitHandler**注解
@RabbitListener 和 @RabbitHandler 搭配使用
@RabbitListener 可以标注在类上面,需配合 @RabbitHandler 注解一起使用
@RabbitListener 标注在类上面表示当有收到消息的时候,就交给 @RabbitHandler 的方法处理,
具体使用哪个方法处理,根据 MessageConverter 转换后的参数类型
@Component
@RabbitListener(queues = "consumer_queue")
public class Receiver {
@RabbitHandler
public void processMessage1(String message) {
System.out.println(message);
}
@RabbitHandler
public void processMessage2(byte[] message) {
System.out.println(new String(message));
}
}
RabbitMQ 的基本配置
#端口号
server:
port: xxx
spring:
rabbitmq:
username: xxx
password: xxx
#虚拟主机 默认为 /
virtual-host: /
host: 192.168.xxx.xxx
port: 5672