RabbitMQ-AMQP术语介绍

生产者发送消息与消费者接受消息流程对比

生产者消费者
连接到RabbitMQ连接到RabbitMQ
获取信道获取信道
声明交换器声明交换器
创建消息声明队列
-----------把队列和交换器绑定起来
发布消息消费消息
关闭信道关闭信道
关闭连接关闭连接

一:消息(message)
——有效荷载(payload):实际的消息内容,比如我要发送:“你好”,那么playload就是一个字符串“你好”
——标签(label):关于payload的一些元数据,比如该数据从哪来,发送到哪,等等

二:生产者(producer)
创建消息,然后将创建的消息发送到代理服务器(RabbitMQ)

三:消费者(consumer)
消费者消费消息的模式有两种:
——持续订阅basic.consume:这是最常用的模式,代理服务器只要来数据,消费者就接收这条数据
——单条订阅basic.get:消费者自己从代理服务器要一条数据,处理完之后,消费者需要再次使用get获取下一条数据,绝大多数情况,我们不应该在一个循环里持续调用get来代替consume,这会消耗性能,从本质上来说,get就是先订阅,然后消费1条数据,之后在取消订阅,这就是get的本质
关于ack值得注意的地方: ack是消费者的属性,所以在消费者端设置,官方原文档说默认情况下是ack=true,但是在rabbit的java客户端中,默认是false的,所以单独使用java客户端的时候,需要手动设置autoAck(示例代码点击这里),同样,官方原文档说ack=false时则rabbit永远不会推送下一条消息,但是我实际使用的情况发现ack=false的时候,消费者依然会接到消息,只不过web管理页面上的unacked的数量一直在增加,很奇怪的现象

四:信道(channel)
如果没有信道,那么生产者线程1发送1条消息应该是这样子的:打开TCP连接,发送消息,关闭TCP连接,当另外一个线程2也发送1条消息的时候,继续打开TCP连接,发送消息,关闭TCP连接,打开和关闭TCP会非常消耗性能,所以AMQP抽象出了信道的概念,多个线程都是用同一个TCP连接,而每个线程第一次发送消息的时候,都会在这个TCP连接上创建一个信道,接下来的每条消息都是通过信道来发送的,对于消费者,也是同样的,在一条TCP上可以创建无穷个信道,AMQP对此没有限制

五:队列(channel.queueDeclare)
消息到达队列之后,如果一个消费者都没有,那么消息就会积压在队列当中,这个时候如果有消费者订阅,那么这些积压的消息将会全部都发送给这个订阅者,需要注意的是队列绝大多数由消费者创建,少情况由生产者创建,所以可以认为消息队列就是由消费者创建即可,rabbit的队列有个特性,与kafka的group相同,都是为了负载均衡,所以当有多个消费者订阅 同一个队列(名称相同就叫同一个队列) 的时候,rabbit会将每个消息只发送给一个订阅者,比如3条消息M1,M2,M3,2个订阅者S1,S2,先把M1给S1,再把M2给S3,再把M3给S1,如果此时S2挂了,那么S1将消费所有的消息

队列属性auto_delete:当该队列上所有的消费者都断开之后,该队列自动删除,即使生产者依然存在并且继续生产消息,也依然会删除该队列,但是如果生产者在消费者从没启动过的情况下启动,并且生产者也创建队列,那么此时该队列会在代理服务器上被创建,且一直堆积生产者的消息,当有消费者连接之后,堆积的消息会发送给消费者,当该消费者断开之后,队列被删除,如果最开始生产者创建队列,并且消费消息,然后自始至终都没有消费者,那么此时断开生产者,队列也会被删除

队列属性exclusive:true是表示该队列是排他队列,排他队列是指其他connection中的channel不可以订阅该队列,下面这段代码就是两个connection,如果将其设置排他队列,那么下面的代码会报错

// 创建一个生产者,开始生产消息
Connection conn1=factory.newConnection();
// 第三个参数true表示q1是个排他队列
conn1.queueDeclare("队列aa",false,true,false,null);
// 创建一个消费者
Connection conn2=factory.newConnection();
// 下面这行代码会报错,因为conn1已经声明了队列aa是排他队列,所以
// conn2不允许再声明队列aa
conn2.queueDeclare("队列aa",false,true,false,null);;

队列属性durable:true表示rabbitMQ崩溃或重启之后,是否重新创建队列(交换器也有这个属性),我们应该将该属性设置成true,默认是false

日记:如果创建相同名称和参数的队列,那么相当于本次没创建队列,并不会覆盖之前的队列,如果创建相同名称且参数不同的队列,那么强烈建议先删除原先队列,然后再创建队列,否则极大可能报错,且报的错与队列重复毫无相关,创建队列是channel.queueDeclare命令,declare的语义是没有则创建

六:交换器(channel.exchangeDeclare)
direct-将消息发送到指定队列中
注意:一个routingKey可以绑定多个队列,direct模式发送消息的时候,是指定哪个exchange的哪个routingKey,由此可见,发送的时候,是与queue无关的,只与exchange和routingKey有关,但是在consumer消费的时候,是指定的哪个queue,由此可见,消费的时候,与exchange和routingKey无关,只与queue有关

fanout-广播,当生产者发送消息到fanout交换器,该交换器上的所有队列都会收到消息,一个生产者,多个消费者

topic-订阅,发布,多个生产者往同一个交换器上的同一个routing key发送消息,订阅该主题该routing key的所有队列都能收到这个消息(注意不是所有消费者都能收到,同一个队列下多个消费者采用轮询机制),所以在topic模式下,routing key就是topic,topic就是routing key
headers(已过时)
交换器属性durable:true表示rabbitMQ崩溃或重启之后,是否重新创建交换器(队列也有这个属性),我们应该将该属性设置成true,默认是false

七:绑定(routing key)
就是将交换器和队列建立一个关系,给交换器起一个别名,比如交换器叫A,routing key是B,该交换器绑定的队列叫C,如果我要使用direct类型的交换器(将消息发送到指定队列中),那么我不能对rabbitMQ说:“帮我把消息发送到A交换器的C队列中”,而应该说:“帮我把消息发送到A交换器,队列绑定的routing key是B的队列中”,虽然本质上是C,但是一个routing key可以绑定多个队列,我想这就是routting key的作用吧?

日记:使用api的时候会发现创建队列和交换器都是declare命令,declare的语义是没有才创建,有就不创建,而不是覆盖,这点需要注意

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值