服务异步通讯---rabbitmq的高级特性

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

MQ常见问题

  • 消息可靠性问题
  • 延迟消息问题
  • 高可用问题
  • 消息堆积问题

一、消息可靠性

确保消息成功发送到消费者

回顾rabbitmq的消息发送过程:

消息发送者发送消息到交换机,交换机根据routing-key将消息路由到队列,队列再将消息投递到消费者。在此过程中,凡是消息传递都可能有消息的丢失。

1.生产者消息确认

确保消息投递到Rabbitmq的队列中

注意在确认机制发送消息时,要给每个消息设置全局唯一id,区分不同消息,避免ack冲突

在 publisher 微服务的application.yml中添加 RabbitMQ 相关配置

  • publisher-confirm-type(支持simple同步等待和correlated异步回调两种类型),生产者确认的开启,此处选择回调模式
  • publisher-returns(开启基于回调的 publish-return 功能)
  • template.mandatory(定义消息路由失败时的策略,true则调用 ReturnCallback,false则直接丢弃消息)

实现 RabbitMQ 生产者在消息发送过程中的确认机制

编写ReturnCallback,全局唯一,单例bean,不能每次发消息时配置,所以要实现ApplicationContextAware接口,在项目启动时注入,(ApplicatiionContext:存放bean的容器,Aware:通知接口。即bean工厂的通知。实现方法即可以得到工厂进而getBean)

与以往不同的是多了中间部分,correlationData封装了消息的唯一id和callback

2.消息持久化

Rabbitmq默认内存存储,如果mq宕机,消息同样可能丢失,要想让消息真正安全,我们必须要使消息持久化,写入磁盘当中。

编写配置类,运行启动类

发送消息进行验证,注意在验证过程中,先把消费者停掉,否则消费者会直接把消息消费。

通过以上持久化操作,手动在mq中publish message,重启mq,交换机和队列仍然运行,保持持久化。可是消息却被销毁了,我们需要操作进行消息的持久化。注意在SpringAMQP中消息 交换机 队列 默认都是持久的

此时重启mq

消息仍然存在,成功完成消息持久化

其实在SpringAMQP中消息 交换机 队列 默认都是持久的



消息同样也是持久化

所以默认情况下,在SpringAMQP中消息 交换机 队列 都是持久的。

因为持久化消息写入磁盘,而不是所有消息都需要写入磁盘,所以我们需要知道它的具体操作流程

3.消费者消息确认

生产者消息确认能够保证生产者把消息投递到mq队列当中

消息持久化能够避免mq宕机导致消息丢失。

消息一定能够投递到消费者,但是消费者一定能够消费吗,如果消费者在消费前宕机呢?

RabbitMQ支持消费者确认机制

此时若抛出异常,消费者返回nack回执给MQ,消息会返回到mq队列,重新发送消息到消费者,无限循环

4.消费失败重试机制


根据配置内容查看控制台,重试次数4次后重试次数耗尽。默认情况下spring在充实次数耗尽后,会把消息丢弃。(返回reject拒绝)

在上述消费者失败重试机制中,消费者出现异常时会利用本地重试,而非无限制的重新入队到队列中。但在重试次数耗尽后,会把消息直接丢弃。

但有些重要的消息是不能直接丢弃的,我们接下来重点分析一下消费者失败消息处理的策略

注意处理器中的交换机名和routingkey与定义接受失败消息的一致。

配置完成或重启服务

在simple.queue发布消息

尝试次数四次后:

Republishing failed message to exchange 'error.direct' with routing key error

显示重发消息到error.direct交换机。

查看error.queue队列中,不仅有消息的内容,还有异常的堆栈信息

生产者 MQ 消费者三个方面确保RabbitMQ消息的可靠性。

二、死信交换机

1.初识死信交换机

如果信息被消费者拒绝,默认情况下会将信息丢弃,如果不想丢弃就需要给队列绑定一个交换机,即为死信交换机。由于交换机不能存储信息,为了让消息不丢失,还要绑定一个队列给死信交换机。死信就可以从死信交换机到达死信队列,便于后续处理

与RepublishMessageRecoverer对比

不同的是前者中所有失败的消息是由消费者投递到交换机的。

而后者是由队列投递到交换机

作用

  • 像Republish的异常交换机一样作为异常消息的兜底方案
  • 处理一些超时消息,功能更加丰富

死信交换机用来处理死信,作为异常消息的兜底方案,处理超市消息

2.TTl

TTL超时分为两种,如果消息和队列都设置了存活时间,则以存活时间更小的那个为准

基于队列设置超时时间为10s,可以根据控制台日志输出验证

接下来为消息设置超时时间为5s,而队列超时时间为10s,有控制台可以得出,超时时间以短的那个为准


准备一个队列,为队列指定一个死信交换机,并用消费者监听私信交换机所在的死信对列,就能实现延迟消息的效果了

3.延迟队列

基于死信交换机实现延迟队列比较麻烦,此处安装DelayExchange插件进行实现

注意:插件属于MQ内部扩展功能,需要找到mq的插件目录,所以在安装mq的时候一定要将其插件目录挂载出去


1.创建交换机,指定类型和路由方式

2.指定延迟时间,发消息时,添加Header"x-delay=时间"

SpringAMQP使用延迟队列插件

  • 声明交换机时设置delayed属性---则为延迟交换机
  • 在发送消息时,set一个"x-delay"头,来设置延迟时间

基于注解(推荐)

基于bean

发送消息添加头信息

因为消息暂存在交换机未到达设置的延迟时间而没有发送到队列,报错,但这样延迟消息不处理会被认为是错误则会被ReturnCallback处理

所以此处我们需要通过message的receievedelay属性来判断消息发送是否失败 是否是延迟消息

三、惰性队列

解决消息堆积的三种思路,前两者是通过消费者角度,后一者则是通过扩大队列容积,提高堆积上限

rabbitmq的队列是基于内存存储的,在高并发场景下,消息量大,如果全部存在内存当中很不现实。mq会设置一个"内存预警",如果内存占用达到上限,就会阻止生产者投递消息到队列中,将这部分消息刷出到磁盘,清理一部分内存空间出来,这个过程就叫做"Page Out"就导致mq会间歇性处于暂停状态,阻止用户写入请求。使得并发能力忽高忽低。

  • 而惰性队列在接收到消息后直接存入磁盘而非内存,很难会出现内存预警

lazy queue

normal queue

四、MQ集群

提高mq的可用性和并发能力

1.普通集群

元信息:只有名字、位置等而没有队列内部的消息

但是访问某节点时,若目标队列没有在该节点,则会从数据所在节点传递到当前节点并返回,注意各个节点没有共享数据,而是引用了其他节点的队列。如果队列所在节点宕机,队列中消息就会丢失

学习过程中用三个docker模拟三个主机


2.镜像集群

若一开始1为主节点,2为镜像节点。1宕机后2会变成主节点,3则会变成镜像节点,集群十分健壮。但再次重启1节点就没有效果了。

3.仲裁队列


JAVA代码创建仲裁队列

总结

本篇通过rabbitmq高级特性讲解解决mq常见问题

  • 消息可靠性问题
  • 延迟消息问题
  • 高可用问题
  • 消息堆积问题
相关推荐
2501_941144422 小时前
Elasticsearch搜索与日志分析实践分享:高性能索引优化与实时检索经验
rabbitmq
2501_941404315 小时前
Go语言高性能WebSocket实时通信实战分享:微服务实时推送与并发优化经验
rabbitmq
2501_941823065 小时前
JavaScript Node.js高并发WebSocket服务设计与实时聊天平台落地经验分享:厦门社交应用实践
rabbitmq
2501_941823375 小时前
区块链与物联网:构建智能化、去中心化的未来生态
rabbitmq
2501_941805936 小时前
人工智能在医疗行业的应用与未来前景:从诊断到个性化治疗的智能革命
rabbitmq
2501_941879818 小时前
Python结合TensorFlow与Flask构建高性能图像识别与分类平台设计与实战分享:南京智慧安防与工业检测落地经验
rabbitmq
2501_941866378 小时前
Python在微服务高并发异步日志采集与分布式监控告警平台中的实践
rabbitmq
print(未来)9 小时前
人工智能与区块链赋能金融互联网应用:智能风控与数字资产创新实践探索》
rabbitmq