MQ 消息队列基本理论(应用场景、产品对比和选型)

本文详细探讨了MQ在互联网项目中的关键作用,通过链式调用实例揭示了其在系统解耦、流量控制和性能优化中的价值。介绍了ActiveMQ、RabbitMQ、RocketMQ和Kafka等主流MQ产品的特性对比,以及在实际项目中的选择策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MQ 基本理论

一、为什么要使用消息中间件呢?

MessageQueue 是一个广泛应用在互联网项目中且非常重要的技术, MessageQueue 通常被用来解决在高并发压力下类似于流量削峰、服务解耦、消息通讯、最终消息一致性等这样的问题。

在认识 MQ-[Message Queue 消息队列]消息中间件的之前,用户对 MQ 没有太直观的感受,MQ-[Message Queue 消息队列] 到底是个什么东西,我需要在项目中使用它吗?使用它不就增加的项目的复杂度吗?

确实,以上问题确实存在,但是在互联网项目中,随着业务的拓展,项目往往面临着越来越高的并发访问,为了解决项目面临的一些问题,项目中不得不引入 MQ 消息中间件。

虽然引入消息中间件不得不让系统处理诸如类似单点故障,数据一致性,接口幂等性等等复杂问题,但是引入 MQ 也是以较小的成本实现提高项目性能的方案之一。

为了让所有人能直观的感受 MQ 消息中间件在应用项目开发中的重大作用,下面我们通过一个小小的实例来进一步详细说明 MQ 在实际的生产环境中到底有什么重大的作用呢?

实例说明:微服务架构下-链式调用

1. 链式调用

链式调用是我们在写程序时候的一般流程,为了完成一个整体功能,会将其拆分成多个函数(或子模块),比如模块 A 调用模块 B,模块 B 调用模块 C,模块 C 调用模块 D。但在大型分布式应用中,系统间的 RPC 交互繁杂,一个功能背后要调用上百个接口并非不可能,那么如果有一个服务出现调用阻塞或者任务处理时间较长,都会造成任务阻塞,甚至服务雪崩的可怕后果。

这些接口之间耦合比较严重,每新增一个下游功能,都要对上游的相关接口进行改造;举个例子:假如系统 A 要发送数据给系统 B 和 C,发送给每个系统的数据可能有差异,因此系统 A 对要发送给每个系统的数据进行了组装,然后逐一发送;当代码上线后,新增了一个需求:把数据也发送给 D。此时就需要修改 A 系统,让他感知到 D 的存在,同时把数据处理好给 D。在这个过程中你会看到,每接入一个下游系统,都要对 A 系统进行代码改造,开发联调的效率很低。

在这里插入图片描述

2. 木桶理论

面对大流量并发时,容易被冲垮。每个接口模块的吞吐能力是有限的,这个上限能力就像是堤坝,当大流量(洪水)来临时,容易被冲垮。

存在性能问题。RPC 接口基本上是同步调用,整体的服务性能遵循“木桶理论”,即链路中最慢的那个接口。比如 A 调用 B/C/D 都是 50ms,但此时 B 又调用了 E,花费2000ms,那么直接就拖累了整个服务性能。更有甚者拖垮整个系统。

在这里插入图片描述

上图画错了,访问BCD的时候50ms应该是500ms
在这里插入图片描述

3. MQ 引入

根据上述的几个问题,在设计系统时可以明确要达到的目标:

  • 1)要做到系统解耦,当新的模块接进来时,可以做到代码改动最小;
  • 2)设置流量缓冲池,可以让后端系统按照自身吞吐能力进行消费,不被冲垮;
  • 3)强弱依赖梳理,将非关键调用链路的操作异步化,提升整体系统的吞吐能力,假设上图中 A、B、C、D 是让用户发起付款,然后返回付款成功提示的几个关键流程,而 B1 是付款后通知商家发货的模块,那么实质上用户对 B1 完成的时间容忍度比较大(比如几秒之后),可以将其异步化。

在现在的系统视线中,MQ 消息队列是普遍使用的,可以完美的解决这些问题的利器。下图是使用了 MQ 的简单架构图,可以看到 MQ 在最前端对流量进行蓄洪,下游的系统A\B\C 只与 MQ 打交道,通过事先定义好的消息格式来解析。
在这里插入图片描述

一般只有写操作用到消息中间件,读不能异步。

二、MQ 应用场景

1. MQ 作用

消息队列作为高并发系统的核心组件之一,能够帮助业务系统解构提升开发效率和系统稳定性。主要具有以下优势:

  • 削峰填谷(大促等流量洪流突然来袭时,MQ 可以缓冲突发流量,避免下游订阅系统因突发流量崩溃)
  • 系统解耦(解决不同重要程度、不同能力级别系统之间依赖导致一死全死)
  • 提升性能(当存在一对多调用时,可以发一条消息给消息系统,让消息系统通知相关系统)
  • 蓄流压测(线上有些链路不好压测,可以通过堆积一定量消息再放开来压测)

2. 应用场景

MQ 可应用在多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、手游、视频、物联网、车联网等。

从应用功能上来讲。例如:

  • 日志监控,作为重要日志的监控通信管道,将应用日志监控对系统性能影响降到最低。
  • 消息推送,为社交应用和物联网应用提供点对点推送,一对多广播式推送的能力。
  • 金融报文,发送金融报文,实现金融准实时的报文传输,可靠安全。
  • 电信信令,将电信信令封装成消息,传递到各个控制终端,实现准实时控制和信息传递。

从功能角度考虑:

  • RocketMQ 在实际应用中常用的使用场景主要有异步处理,应用解耦,流量削锋和消息通讯四个场景

2.1 异步处理

场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种:

1.串行的方式
2.并行方式

  • a、串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。
    在这里插入图片描述
  • b、并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间
    在这里插入图片描述

假设三个业务节点每个使用 50 毫秒钟,不考虑网络等其他开销,则串行方式的时间是 150 毫秒,并行的时间可能是 100 毫秒。 因为 CPU 在单位时间内处理的请求数是一定的,假设 CPU1 秒内吞吐量是 100 次。则串行方式 1 秒内 CPU 可处理的请求量是 7 次(1000/150)。并行方式处理的请求量是 10 次(1000/100)

小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢?

  • 引入消息队列,将不是必须的业务逻辑,异步处理。改造后的架构如下:
    在这里插入图片描述
    按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是 50 毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是 50 毫秒。因此架构改变后,系统的吞吐量提高到每秒 20 QPS。比串行提高了 3 倍,比并行提高了两倍。

2.2 应用解耦

场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。如下图:
在这里插入图片描述

传统模式的缺点:假如库存系统无法访问,则订单减库存将失败,从而导致订单失败,订单系统与库存系统耦合

如何解决以上问题呢?引入应用消息队列后的方案,如下图:
在这里插入图片描述

订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功

库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作

假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦

2.3 流量削锋

流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。 应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。

a、可以控制活动的人数
b、可以缓解短时间内高流量压垮应用
在这里插入图片描述
用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面。 秒杀业务根据消息队列中的请求信息,再做后续处理

在这里插入图片描述
小公司小项目,用消息中间件比较浪费(一般搭建消息中间件,都需要至少2台以上机器,主从架构),可以使用Java本身的队列实现

2.4 日志处理

日志处理是指将消息队列用在日志处理中,比如 Kafka 的应用,解决大量日志传输的问题。架构简化如下

在这里插入图片描述
日志采集客户端,负责日志数据采集,定时写入 Kafka 队列
Kafka 消息队列,负责日志数据的接收,存储和转发
日志处理应用:订阅并消费 kafka 队列中的日志数据

2.5 消息通讯

消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等

  • 点对点通讯:
    在这里插入图片描述
    客户端 A 和客户端 B 使用同一队列,进行消息通讯。

  • 聊天室通讯:
    在这里插入图片描述
    客户端 A,客户端 B,客户端 N 订阅同一主题,进行消息发布和接收。实现类似聊天室效果。

以上实际是消息队列的两种消息模式,点对点或发布订阅模式。模型为示意图,供参考。

2.6 示例

电商系统:
在这里插入图片描述
消息队列采用高可用,可持久化的消息中间件。比如 Active MQ,Rabbit MQ,RocketMq。

日志收集系统:
在这里插入图片描述

事务处理:
银行 A 银行 B 进行转账,使用 mq 消息中间件来保证不同的系统之间的数据一致性。
在这里插入图片描述

三、MQ 产品对比

在这里插入图片描述

目前主流的 MQ 主要有

  • ZeroMQ
  • 推特的 Distributedlog
  • ActiveMQ:Apache 旗下的老牌消息引擎(功能、API很完备,但是消息堆积能力,时效性不能满足互联网项目要求)
  • RabbitMQ:AMQP 的默认实现。(go语言开发的,时效性非常强,微秒级别,消息堆积能力弱一点)
  • Kafka:AMQP 的默认实现。(主要做日志收集的流量缓冲)
  • RocketMQ:天然分布式架构
  • Artemis:Apache 的 ActiveMQ 下的子项目
  • Apollo:阿波罗,同样为 Apache 的 ActiveMQ 的子项目的号称下一代消息引擎
  • 商业化的消息引擎 IronMQ
  • 实现了 JMS(Java Message Service)标准的 OpenMQ

那么这些消息中间件都有什么特性呢?

1. ActiveMQ

单机吞吐量:万级
时效性:ms 级
可用性:高,基于主从架构实现高可用性
消息可靠性:有较低的概率丢失数据(AP模型)
功能支持:MQ 领域的功能极其完备

总结:

  • 1)非常成熟,功能强大,在早些年业内大量的公司以及项目中都有应用
  • 2)偶尔会有较低概率丢失消息
  • 3)现在社区以及国内应用都越来越少,官方社区现在对 ActiveMQ 5.x 维护越来越少,几个月才发布一个版本
  • 4)主要是基于解耦和异步来用的,较少在大规模吞吐的场景中使用

2. RabbitMQ

单机吞吐量:万级
topic 数量对吞吐量的影响:topic越多,吞吐量越低
时效性微秒级,延时低是一大特点。
可用性:高,基于主从架构实现高可用性
消息可靠性:经过参数优化配置,消息可以做到 0 丢失
功能支持:基于 erlang 开发,所以并发能力很强,性能极其好,延时很低

总结:

  • 1)erlang 语言开发,性能极其好,延时很低;
  • 2)吐量到万级,MQ 功能比较完备
  • 3)开源提供的管理界面非常棒,用起来很好用
  • 4)社区相对比较活跃,几乎每个月都发布几个版本分
  • 5)在国内一些互联网公司近几年用 rabbitmq 也比较多一些 但是问题也是显而易见的,RabbitMQ 确实吞吐量会低一些,这是因为他做的实现机制比较重。
  • 6)erlang 开发,很难去看懂源码,基本职能依赖于开源社区的快速维护和修复bug。
  • 7)rabbitmq 集群动态扩展会很麻烦,不过这个我觉得还好。其实主要是 erlang 语言本身带来的问题。很难读源码,很难定制和掌控。

3. RocketMQ

单机吞吐量十万级
topic 数量对吞吐量的影响:topic 可以达到几百,几千个的级别,吞吐量会有较小幅度的下降。可支持大量 topic 是一大优势。
时效性:ms 级
可用性:非常高,分布式架构
消息可靠性:经过参数优化配置,消息可以做到 0 丢失
功能支持:MQ 功能较为完善,还是分布式的,扩展性好

总结:

  • 1)接口简单易用,可以做到大规模吞吐,性能也非常好,分布式扩展也很方便,社区维护还可以,可靠性和可用性都是 ok 的,还可以支撑大规模的 topic 数量,支持复杂MQ 业务场景
  • 2)而且一个很大的优势在于,源码是 java,我们可以自己阅读源码,定制自己公司的 MQ,可以掌控
  • 3)社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准 JMS 规范走的有些系统要迁移需要修改大量代码相比于其他的 mq 消息中间件具有主要优势特性有:
    • 支持事务型消息(消息发送和 DB 操作保持两方的最终一致性,rabbitmq 和 kafka 不支持)
    • 支持结合 rocketmq 的多个系统之间数据最终一致性(多方事务,二方事务是前提)
    • 支持 18 个级别的延迟消息(rabbitmq 和 kafka 不支持)
    • 支持指定次数和时间间隔的失败消息重发(kafka 不支持,rabbitmq 需要手动确认)
    • 支持 consumer 端 tag 过滤,减少不必要的网络传输(rabbitmq 和 kafka 不支持)
    • 支持重复消费(rabbitmq 不支持,kafka 支持)

4. Kafka

单机吞吐量十万级,最大的优点,就是吞吐量高。
topic 数量对吞吐量的影响:topic 从几十个到几百个的时候,吞吐量会大幅度下降。所以在同等机器下,kafka 尽量保证 topic 数量不要过多。如果要支撑大规模 topic,需要增加更多的机器资源
时效性:ms 级
可用性:非常高,kafka 是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
消息可靠性:经过参数优化配置,消息可以做到 0 丢失
功能支持:功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用

总结:

  • 1)kafka 的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms 级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展
  • 2)同时 kafka 最好是支撑较少的 topic 数量即可,保证其超高吞吐量
  • 3)kafka 唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略

5. 对比图

在这里插入图片描述

消息堆积、消息量很大,则选RocketMQ
消息量级不是很大,追求时效性比较高,用RabbitMQ

四、产品选型

1. 引入 MQ 的缺点

在这里插入图片描述

项目引入 RocketMQ 消息中间件或其他的消息中间件产品是否会对整个项目带来风险呢?一个使用了 MQ 的项目,如果连这个问题都没有考虑过,就把 MQ 引进去了,那就给自己的项目带来了风险。我们引入一个技术,要对这个技术的弊端有充分的认识,才能做好预防。要记住,不要给公司挖坑!否则后果很严重啊!那么使用 rocketmq 等消息中间件会给应用项目带来什么样的问题呢?答案有如下几点

  • 系统可用性降低:本来其他系统只要运行好好的,那你的系统就是正常的。现在你非要加个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性降低
  • 系统复杂性增加:要多考虑很多方面的问题,比如一致性问题、如何保证消息不被重复消费,如何保证保证消息可靠传输。因此,需要考虑的东西更多,系统复杂性增大。

既然有这些缺点,那么是不是不敢使用 MQ 了呢?答案很明显,不是,为了提高项目的性能,构建松耦合、异步的结构,必须要使用 MQ.

因此这个是一个矛盾的话题,其实也不矛盾,在一些初创型企业或者中小型公司,服务拆分架构没有太多,并发流量也不是很大,很显然没必要引入 mq. 但是在现在互联网的产品开发中,企业往往要求产品快速迭代,实现可持续交付,高扩展性,可持续部署的能力,因此项目架构往往采用 SOA,或微服务架构,那么在引入消息中间件也成为必然。所以关于是否使用 mq 消息中间件的问题,就已经非常清楚了。

2. 产品选型

一般的业务系统要引入 MQ,最早大家都用 ActiveMQ,但是现在确实大家用的不多了,没经过大规模吞吐量场景的验证,社区也不是很活跃。

后来大家开始用 RabbitMQ,但是确实 erlang 语言阻止了大量的 java 工程师去深入研究和掌控他,对公司而言,几乎处于不可控的状态,但是确实呢这个产品是开源的,比较稳定的支持,活跃度也高;

不过现在确实越来越多的公司,会去用 RocketMQ,确实很不错,RocketMQ 是一个天然的分布式的消息中间件,性能及其出色,且支持事务消息,能力强劲。

如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。

中小型软件公司,建议选 RabbitMQ,一方面,erlang 语言天生具备高并发的特性,而且他的管理界面用起来十分方便。正所谓,成也萧何,败也萧何!他的弊端也在这里,虽然RabbitMQ 是开源的,然而国内有几个能定制化开发 erlang 的程序员呢?所幸,RabbitMQ的社区十分活跃,可以解决开发过程中遇到的 bug,这点对于中小型公司来说十分重要。不考虑 rocketmq 和 kafka 的原因是,一方面中小型软件公司不如互联网公司,数据量没那么大,选消息中间件,应首选功能比较完备的,所以 kafka 排除。可以考虑阿里的 rocketmq.

大型软件公司,根据具体使用在 rocketMq 和 kafka 之间二选一。一方面,大型软件公司,具备足够的资金搭建分布式环境,也具备足够大的数据量。针对 rocketMQ,大型软件公司也可以抽出人手对 rocketMQ 进行定制化开发,毕竟国内有能力改 JAVA 源码的人,还是相当多的。至于 kafka,根据业务场景选择,如果有日志采集功能,肯定是首选 kafka 了。具体该选哪个,看使用场景。

我们在进行中间件选型时,一般都是通过下面几点来进行产品选型的:

 1)性能
 2)功能支持程度
 3)开发语言(团队中是否有成员熟悉此中间件的开发语言,市场上此种语言的开发人员是否好招)
 4)有多少公司已经在生产环境上实际使用过,使用的效果如何
 5)社区的支持力度如何
 6)中间件的学习程度是否简单、文档是否详尽
 7)稳定性
 8)集群功能是否完备

如果从以上 8 点来选型一个消息队列,作为一名熟悉 java 的程序员,当遇到重新选择消息队列的场景时,我会毫不犹豫的选型 rocketmq,rocketmq 除了在第 5 点上表现略差(文档少,学习成本高)以及监控管理功能不友好外,从其它方面来说,它真的是一款非常优秀的消息队列中间件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

犬豪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值