RabbitMQ采用AMQP高级新消息队列协议的一种消息队列技术,最大的特点是消费并不需要确保提供方实现,实现了服务之间的高度解耦
延迟队列存储的对象肯定是对应的延迟消息,所谓”延迟消息”是指当消息被发送以后,并不想让消费者立即拿到消息,而是等待指定时间后,消费者才拿到这个消息进行消费
TTL(Time To Live)
RabbitMQ可以针对Queue和Message设置 x-message-tt,来控制消息的生存时间,如果超时,则消息变为dead letter
RabbitMQ针对队列中的消息过期时间有两种方法可以设置。
A: 通过队列属性设置,队列中所有消息都有相同的过期时间。
B: 对消息进行单独设置,每条消息TTL可以不同。
给对列设置过期时间,将消息加入对列,过期时间之后消息自动进入死信队列,监听死信队列,进行消费操作可以实现延迟队列
消息丢失,消息重复消费等等
将信道设置成confirm模式(发送方确认模式)
,则所有在信道上发布的消息都会被指派一个唯一ID。一旦消息被投递到目的队列后,或者消息被写入磁盘后,信道会发送一个确认给生产者(包括消息的ID)。
如果RabbitMQ发生内部错误从而导致消息丢失,会发送一条nack消息。
发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。
当确认消息到达生产者应用程序,生产者应用的回调方法就会被触发来处理确认消息。
消费者接受每一条消息后都必须进行确认,只要有消费者确认了消息,MQ才能安全的把消息从队列中删除。
这里并没有用到超时机制,MQ仅通过Consumer的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ给了Consumer足够长的时间来处理消息。保证了数据的最终一致性。
还有几种情况:
在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重的依据(消息投递失败并重传),避免重复的消息进入队列,在消息消费时,要求消息体中 必须要有一个bizID(对于同一个业务全局唯一)
作为去重的依据,避免同一条消息被重复消费。
由于 TCP 连接的创建和销毁开销较大
,且并发数受系统资源限制,会造成性能瓶颈。RabbitMQ 使用信道的方式来传输数据。信道是建立在真实的 TCP 连接内的虚拟连接,且每条 TCP 连接上的信道数量没有限制
。
no_act
设置是否确认消息处理完?
Direct:直连模式
Topic: 转发模式
Topic 模式
下可以使用统配符表示bingKey
:’*'表示匹配一个单词, '#'则表示匹配没有或者多个单词。由此可以实现一个queue
接收多个路由的消息。
Fanout :广播模式
广播模式下,不用理会routing key
。Fanout Exchange 会将消息传递到 exchange 绑定好的 queue list 上去。
可以选择使用 RabbitMQ 提供事务功能,就是生产者在发送数据之前开启事务,然后发送消息,如果消息没有成功被RabbitMQ接收到,那么生产者会受到异常报错,这时就可以回滚事物,然后尝试重新发送;如果收到了消息,那么就可以提交事物。
缺点: RabbitMQ 事务已开启,就会变为同步阻塞操作,生产者会阻塞等待是否发送成功,太耗性能会造成吞吐量的下降。
还有就是上面的第五点
持久化
使用 RabbitMQ 提供的 ACK 机制,首先关闭 RabbitMQ 的自动ACK,然后每次在确保处理完这个消息之后,在代码里手动调用 ACK。这样就可以避免消息还没有处理完就ACK。
把消息压入RabbitMQ中可以缓冲系统压力。比如现在系统只能接受2000请求,但是一下子有10000个请求过来,那么这个请求就会压在RabbitMQ中,那么就可以慢慢进行消费了。
以前是先去发短信,再去发邮件。引入RabbitMQ之后,我们就可以进行在发短信的同时再去发邮箱。
当多个系统耦合在一起的时候,系统的消息会发送给连在一起的系统,但是这个消息有些系统可能是不需要的。所以引入了之后,很方便将这个系统进行解耦,每个系统需要的就在消息队列解耦。
虽然能提供削峰,异步,解耦,但是这个还是有很多要考虑的问题,消息丢失,重复消费。
当消息一旦被消费者接收,队列中的消息就会被删除。那么问题来了:RabbitMQ怎么知道消息被接收了呢?
这就要通过消息确认机制(Acknowlege)
来实现了。当消费者获取消息后,会向RabbitMQ发送回执ACK
,告知消息已经被接收。不过这种回执ACK分两种情况:
这两ACK要怎么选择呢?这需要看消息的重要性: