消息中间件的使用场景,流行的消息中间件有哪些?

25,623次阅读
没有评论

共计 3157 个字符,预计需要花费 8 分钟才能阅读完成。

应用场景

1. 业务场景

对于一个电商 APP 而言,每卖掉了一个商品,就要扣减掉商品的库存,而且一旦用户成功支付了,还需要将订单的状态更新成待发货。

消息中间件的使用场景,流行的消息中间件有哪些?

电商系统

在完成这些最核心的功能后,其实是有很多事情要做的,如果这些动作都以同步方式来完成,根据线上系统的一般统计,多个子步骤全部执行完毕,加起来大概需要 1 秒~2 秒的时间。

有时候在高峰期并发量特别大,服务器的磁盘、IO、CPU 的负载会很高,执行 SQL 语句的性能也会有所下降。因此有的时候甚至需要几秒钟的时间完成上述几个步骤。

想象一下,如果你是一个用户,在支付完一个订单之后,界面上会有一个圈圈不停的旋转,让你等待好几秒之后才能提示支付成功。对用户来说几秒钟的时间,会让人非常不耐烦的!

2. 解决问题

所以首先针对子步骤过多、速度过慢、让用户支付之后等待时间过长的问题,就是订单系统急需解决的问题!

而解决这个问题的一大利器就是消息中间件,英文全称“Message Queue”,简称 MQ。

消息中间件的使用场景,流行的消息中间件有哪些?

架构

在引入消息中间件以后,系统 A 和系统 B 之间就由同步变为异步通信,而完成这样的一个核心概念就是“消息”。

系统 A 发送消息给 MQ 后,就认为已经完成了自己的任务;然后系统 B 根据自己的情况,可能会在系统 A 投递消息到 MQ 之后的 1 秒内,也可能是 1 分钟之后,也可能是 1 小时之后,多长时间都有可能。

反正不管是多长时间后,系统 B 会根据自己的节奏从 MQ 里获取到一条属于自己的消息,再根据消息的指示完成自己的工作。

在“异步调用”的整个过程中,系统 A 仅仅是发个消息到 MQ,至于系统 B 什么时候获取消息,有没有获取消息,系统 A 是不管的。

消息队列

当我们在使用一个消息队列时,希望它的功能如下:

  • 支持阻塞等待拉取消息
  • 支持发布 / 订阅模式
  • 消费失败,可重新消费,消息不丢失
  • 实例宕机,消息不丢失,数据可持久化
  • 消息可堆积

顺着这个思路,再重新思考一下订单系统。由于支付订单流程中,过多的子步骤如红包发放、短信 push 通知、积分等等导致性能很差。

在引入 MQ 后,可以让订单系统仅仅完成最核心的功能,然后发送消息到 MQ。比如需要进行减库存,就发送一个消息到库存消息队列中,然后库存系统从这个 MQ 里获取消息再进行处理就可以,把这些很耗时的步骤慢慢执行,从而也实现了系统之间的解耦。

在大促活动的时候,同样可以让瞬间涌入的大量下单请求到 MQ 里去排队,然后让订单系统在后台慢慢的获取订单,以数据库可以接受的速率完成操作,避免瞬间请求量过大击垮数据库。

这也是 MQ 的另一重要功能:削峰填谷。

所谓消息中间件,就是一种系统,它自己本身也是独立部署的,通过消息的收发,是多个系统之间不局限于同步调用,通过异步调用更好地实现解耦。

目前业界使用最广泛的是 Kafka、RabbitMQ 以及 RocketMQ 这三种消息中间件。

Redis 消息队列

Redis 很轻量,自带好几种可以用来实现消息队列的功能,用来作队列也很方便。

  • list 链表
  • 订阅 / 发布
  • Redis Stream

1.pub/sub 优缺点

Pub/Sub 的优缺点:

  • 支持发布 / 订阅,支持多组生产者、消费者处理消息
  • 消费者下线,数据会丢失
  • 不支持数据持久化,Redis 宕机,数据也会丢失
  • 消息堆积,缓冲区溢出,消费者会被强制踢下线,数据也会丢失
消息中间件的使用场景,流行的消息中间件有哪些?

Pub/Sub

Pub/Sub 缓冲区是有「上限」的(可配置),如果消费者拉取消息很慢,就会造成生产者发布到缓冲区的消息开始积压,缓冲区内存持续增长。

如果超过了缓冲区配置的上限,此时,Redis 就会「强制」把这个消费者踢下线。

这时消费者就会消费失败,也会丢失数据。

如果你有看过 Redis 的配置文件,可以看到这个缓冲区的默认配置:client-output-buffer-limit pubsub 32mb 8mb 60。

  • 32mb:缓冲区一旦超过 32MB,Redis 直接强制把消费者踢下线
  • 8mb + 60:缓冲区超过 8MB,并且持续 60 秒,Redis 也会把消费者踢下线

2.stream

Stream 通过 XADD 和 XREAD 完成最简单的生产、消费模型:

  • XADD:发布消息
  • XREAD:读取消息

Stream 通过以下命令完成发布订阅:

  • XGROUP:创建消费者组
  • XREADGROUP:在指定消费组下,开启消费者拉取消息

Stream 保证消息不丢失,重新消费的方式:

当一组消费者处理完消息后,需要执行 XACK 命令告知 Redis,这时 Redis 就会把这条消息标记为「处理完成」。

// group1 下的 1618472043089-0 消息已处理完成
127.0.0.1:6379> XACK queue group1 1618472043089-0

如果消费者异常宕机,肯定不会发送 XACK,那么 Redis 就会依旧保留这条消息。

待这组消费者重新上线后,Redis 就会把之前没有处理成功的数据,重新发给这个消费者。这样一来,即使消费者异常,也不会丢失数据了。

Stream 处理消息堆积:

在发布消息时,可以指定队列的最大长度,防止队列积压导致内存爆炸。

// 队列长度最大 10000
127.0.0.1:6379> XADD queue MAXLEN 10000 * name zhangsan
"1618473015018-0"

当队列长度超过上限后,旧消息会被删除,只保留固定长度的新消息。

Kafka

1. 优势

  • Kafka 的吞吐量几乎是行业里最优秀的,在常规的机器配置下,一台机器可以达到每秒十几万的 QPS,可谓是消息中间件中的顶尖水平。
  • 性能高,发送消息给 Kafka 可以控制在毫秒级。
  • 可用性高,Kafka 能够支持集群部署,如果部分服务器发生了宕机,集群其余部分可以保证任务的继续运行。

2. 劣势

  • Kafka 的存储策略是在消息收到之后,将其写入磁盘缓冲区内,并不会直接存储到物理硬盘上。这就导致了假如机器本身发生故障,磁盘缓冲区里的数据非常有可能丢失。而消息作为最重要的资源,kafka 的这一特点有可能造成严重后果。
  • Kafka 另外一个比较大的缺点是功能比较单一。它使用了典型的推拉架构设计,生产者将发送消息给它,然后消费者在从它拉取消息进行消费。除此之外,其他就没有什么额外的高级功能,所以基于 Kafka 有限的功能,一些比较复杂的商业场景并不是很适合。

RabbitMQ

再说 RabbitMQ,在 RocketMQ 出现之前,国内大部分公司,包括很多一线互联网大厂都在使用 RabbitMQ,而且直到目前,还有很多中小型公司在使用 RabbitMQ。

1. 优势

  • 可以有保证数据不丢失的机制。
  • 保证高可用性,集群部署的时候部分,即使部分服务器宕机可以继续执行任务。
  • 实现了部分高级功能,比如死信队列,消息重试。

2. 劣势

  • RabbitMQ 的吞吐量是比较低,只有每秒几万的级别,遇到像双十一这样的高并发场景,很容易到达性能的瓶颈。
  • 维护比较复杂,在集群部署时,如果需要线性扩展,比较麻烦。
  • 它的开发语言是 erlang,国内目前大大小小公司的技术骨干大部分都是 BAT 背景,精通 erlang 语言的还是少数。阅读源代码非常困难,也就更加无从谈起根据个性化要求修改源代码了

RocketMQ

RocketMQ 是阿里开源的消息中间件,经过实战的检验,比较靠谱。后发优势使它在最初设计的时候,就为了去解决 Kafka 和 RabbitMQ 所存在的缺陷。

1. 优势

  • 性能强大,吞吐量高,能够达到 10 万 QPS 以上的级别
  • 可以保证高可用性,能够大规模集群化部署
  • 支持通过配置保证数据绝对不丢失
  • 满足多种需求,比如说延迟消息、事务消息、消息回溯、死信队列、消息积压等等。
  • RocketMQ 是基于 Java 开发的,符合国内大多数公司的技术栈,很容易就可以阅读他的源码,甚至是修改他的源码。

2. 劣势

  • 当然 RocketMQ 也有美中不足的地方,RocketMQ 的官方文档相对简单,而这也是国内开源软件和社区的一个通病,可能国内 996 的工作强度导致大家没有更多的精力维护。

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-09-10发表,共计3157字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)