消息队列详解

消息队列知识图谱

在这里插入图片描述

为什么需要消息队列

以秒杀系统设计为例,说明消息队列的应用场景。

异步处理

举例 :订单下单的异步化处理

在这里插入图片描述

在这里插入图片描述
存在的优点:

  • 可以更快地返回结果;
  • 减少等待,自然实现了步骤之间的并发,提升系统总体的性能

流量控制(削峰)

举例: 如何避免过多的请求压垮我们的秒杀系统?使用消息队列隔离网关和后端服务,以达到流量控制和保护后端服务的目的

加入消息队列后,整个秒杀流程变为:
1、网关在收到请求后,将请求放入请求消息队列;
2、后端服务从请求消息队列中获取 APP 请求,完成后续秒杀处理过程,然后返回结果
在这里插入图片描述
或者使用消息队列充当令牌桶的作用
在这里插入图片描述

这样做的好处,可以避免大量的请求给后端服务增加过大的压力,而且可以比较方便的扩充后端服务的实例。但同时带来的缺点是:
1、增加了系统调用链环节,导致总体的响应时延变长。
2、上下游系统都要将同步调用改为异步消息,增加了系统的复杂度。

服务解耦

消息队列的另外一个作用,就是实现系统应用之间的解耦。再举一个电商的例子来说明解耦的作用和必要性。
直接调用的形式:
在这里插入图片描述
消息队列解耦
在这里插入图片描述
除此之外消息队列还有如下应用场景:
1、作为发布 / 订阅系统实现一个微服务级系统间的观察者模式;
2、连接流计算任务和数据;
3、用于将消息广播给大量接收者。
同时在了解消息队列的应用场景下,我们还应当认识到消息队列自身的一些局限性
1、引入消息队列带来的延迟问题;
2、增加了系统的复杂度;
3、可能产生数据不一致的问题。如要保持强一致性,需要高代价的补偿(如分布式事务、对账),有数据丢失风险,如宕机重启,如要保证队列数据可用,需要额外机制保证(如双活容灾)

其他的问题

**问题1 :**MQ有消息堆积的能力,Redis作为一个高性能缓存有时候也作为队列来使用,那是否适合使用Redis来替代MQ应对消息堆积呢?
解答:Redis高性能是相对于主流数据库而言,一般能达到几万TPS,而现代消息队列很轻松可以达到十几万TPS;如果挤压的消息比较多,这时候需要考虑选择的MQ消息堆积的能力,在集中主流的消息队列中,RocketMQ,Kafka,Plusar要比RabbitMQ

该如何选择消息队列

选择消息队列的基本标准
	必须是开源的
	选择的产品必须是流行且社区活跃度比较高

另外作为消息队列,还应该具备如下几个要求
	消息的可靠传递:确保不丢消息
	Cluster:支持集群,确保不会因为某个节点宕机导致服务不可用,当然也不能丢消息
	性能:具备足够好的性能,能满足绝大多数场景的性能要求。

RabbitMQ

  • 开发语言:Erlang

  • 架构
    在这里插入图片描述

  • 支持协议: AMQP

  • 缺点:第一个问题是,RabbitMQ 对消息堆积的支持并不好;第二个问题是,RabbitMQ 的性能是我们介绍的这几个消息队列中最差的,依据硬件配置的不同,它大概每秒钟可以处理几万到十几万条消息。

    选择中间件的考量维度:可靠性,性能,功能,可运维行,可拓展性,是否开源及社区活跃度
    rabbitmq:
    优点:轻量,迅捷,容易部署和使用,拥有灵活的路由配置
    缺点:性能和吞吐量较差,不易进行二次开发
    rocketmq:
    优点:性能好,稳定可靠,有活跃的中文社区,特点响应快
    缺点:兼容性较差,但随意影响力的扩大,该问题会有改善
    kafka:
    优点:拥有强大的性能及吞吐量,兼容性很好
    缺点:由于“攒一波再处理”导致延迟比较高
    pulsar:
    采用存储和计算分离的设计,是消息队里产品中黑马,值得持续关注

消息模型:主题和队列有什么区别?

队列模型

在这里插入图片描述

主题模型

在这里插入图片描述

RocketMQ消息模型

topic :一类消息,如订单付款成功消息
Queue:一个topic可以对应多个队列,同一个消费者组的消费者只能消费一个队列的消息,消费组维护自己在队列中读取消息的位置。
消费者组
生产者

RocketMQ如何保证消息的顺序性:
消息生产者根据消息的一些标识信息,如订单ID,用户id通过一致性hash算法保证消息发送到相同的队列上。就可以确保严格顺序了。
RocketMQ如何保证消息的不丢失:
通过消息确认机制,为了不影响消息的发送效率,rocket是批量确认消息的。

消息队列是如何实现分布式事务的?

如何确保消息不会丢失?

检测消息丢失的方法

像 Kafka 和 RocketMQ 这样的消息队列,它是不保证在 Topic 上的严格顺序的,只能保证分区上的消息是有序的,所以我们在发消息的时候必须要指定分区,并且,在每个分区单独检测消息序号的连续性。

消息丢失可能发生的位置
在这里插入图片描述

生产阶段: 在这个阶段,从消息在 Producer 创建出来,经过网络传输发送到 Broker 端。
存储阶段: 在这个阶段,消息在 Broker 端存储,如果是集群,消息会在这个阶段被复制到其他的副本上。
消费阶段: 在这个阶段,Consumer 从 Broker 上拉取消息,经过网络传输发送到 Consumer 上。

生产阶段

对消息的发送结果进行检查
异步发送时需要注意重新发送回调函数
设置producer的重试策略

Broker 存储阶段
默认情况下,消息只要到了 Broker 端,将会优先保存到内存中,然后立刻返回确认响应给生产者。随后 Broker 定期批量的将一组消息从内存异步刷入磁盘。

这种方式减少 I/O 次数,可以取得更好的性能,但是如果发生机器掉电,异常宕机等情况,消息还未及时刷入磁盘,就会出现丢失消息的情况。
结合生产阶段与存储阶段,若需要严格保证消息不丢失,broker 需要采用如下配置:
在这里插入图片描述
消费阶段
消费者从 broker 拉取消息,然后执行相应的业务逻辑。一旦执行成功,将会返回ConsumeConcurrentlyStatus.CONSUME_SUCCESS 状态给 Broker。

如何处理消费过程中的重复消息

我们现在常用的绝大部分消息队列提供的服务质量都是 At least once,包括 RocketMQ、RabbitMQ 和 Kafka 都是这样。也就是说,消息队列很难保证消息不重复。我们现在常用的绝大部分消息队列提供的服务质量都是 At least once,包括 RocketMQ、RabbitMQ 和 Kafka 都是这样。也就是说,消息队列很难保证消息不重复。

幂等性解决方案

利用数据库的唯一约束实现幂等

在分库分表的情况下存在问题

查询判断再修改

存在并发安全问题

分布式锁方案

在锁过期的情况下,异常情况,如网络不稳定还是存在多次执行的可能。

分布式锁加日志判断方案

总结

在这里插入图片描述

如何实现高性能的分布式程序

  1. 使用异步设计的方法
  2. 异步网络IO
  3. 专用序列化、反序列化方法
  4. 设计良好的传输协议
  5. 双工通讯

Kafka如何实现高性能IO?

使用批量发送消费机制

kafka在发送端的SDK中,不管是producer是发送一条很少多条消息,客户端都是先缓存到内存中再批量发送到broker,broker也不对这些消息进行解包,一次性存下来。而在消费端sdk,也是批量获取消息,再有消费端来解包,一条条处理。所有broker的压力比较小。

使用顺序读写提升磁盘 IO 性能

利用 PageCache 加速消息读写

ZeroCopy:零拷贝技术

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sjhzjj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值