什么是消息队列?
发布/订阅消息收发
为什么使用消息队列?
消息队列有什么优点和缺点?
消息队列中间件
Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么区别,以及适合哪些场景?
IoT领域中的消息队列应用
什么是消息队列?
消息队列是一种异步的服务间通信方式,使用于无服务和微服务架构。消息在被处理和删除之前一直存储在队列上。每条消息仅可被一直为用户处理一次。消息队列可被用于分离重量级处理、缓存或批处理工作以及缓解高峰期工作负载。
在现代云架构中,应用程序被分解为多个规模较小且更易于开发、部署和维护的独立构建模块。消息队列可为这些分布式应用程序提供通信和协调。消息队列可以显著简化分离应用程序的编码,同时提高性能、可靠性和可扩展性。
借助消息队列,系统的不同部分可相互通信并异步执行处理操作。消息队列提供一个临时存储消息的轻量级缓存区,以及允许软件组件连接到队列以发送接受消息的终端节点。这些消息通常较小,可以是请求、恢复、错误消息或明文消息等。要发送消息时,一个名为“创建器”的组件将消息添加到队列。消息将存储在队列中,直至名为“处理器”的另一组件检索该消息并执行相关操作。
许多创建器和处理器都可以使用队列,但一条信息只能有一盒处理器处理一次。因此,这种消息收发模式通常称为一对一或点对点通信。如果消息需要由多个处理器进行处理,可采用扇出设计模式将消息队列与发布/订阅消息收发结合起来。
发布/订阅消息收发是一种异步的服务间通信方式,适用于无服务和微服务架构。在发布/订阅模式下,发布到主题的任何的任何消息都会立即被主题的所有订阅者接受。发布/订阅消息收发可用于启用事件驱动架构,或分离应用程序,以提高性能、可靠性和可扩展性。
发布/订阅消息收发基础知识
在现代云架构中,应用程序被分解为多个规模较小且易于开发、部署和维护的独立构建块。发布/订阅消息收发可以为这些分布式应用程序提供及时事件通知。
发布/订阅模式让消息能够异步广播到系统中的不同部分。消息主题与消息队列类似,可以提供一个轻量型机制来广播异步事件通知,还可以提供能让软件组件连接主题以便发送和接受消息的终端节点。在广播消息时,一个叫做“发布者”的组件会将消息推送到主题。与在消息被检索前批量处理消息的消息队列不同的是,消息主题无需或使用极少消息队列即可传输消息,并将消息立即推送给所有订阅者。订阅该主题的所有组件都会收到广播的每一条消息,除非订阅着设置了消息筛选策略。
消息主题的订阅着通常执行不同的功能,并可以同时对消息执行不同的操作。发布者无需知道谁在使用广播的消息而订阅着也无需知道消息来自哪里。这种消息收发模式与消息队列稍有不同,在消息队列中,发送消息的组件通常知道发送目的地。
其实就是问问你消息队列都有哪些使用场景,然后你项目里具体是什么场景,说说你在这个场景里用消息队列是什么?
面试官问你这个问题,期望的一个回答是说,你们公司有个什么业务场景,这个业务场景有个什么技术挑战,如果不用 MQ 可能会很麻烦,但是你现在用了 MQ 之后带给了你很多的好处。
先说一下消息队列常见的使用场景吧,其实场景有很多,但是比较核心的有 3 个:解耦、异步、削峰。
解耦
看这么个场景。A 系统发送数据到 BCD 三个系统,通过接口调用发送。如果 E 系统也要这个数据呢?那如果 C 系统现在不需要了呢?A 系统负责人几乎崩溃......
在这个场景中,A 系统跟其它各种乱七八糟的系统严重耦合,A 系统产生一条比较关键的数据,很多系统都需要 A 系统将这个数据发送过来。A 系统要时时刻刻考虑 BCDE 四个系统如果挂了该咋办?要不要重发,要不要把消息存起来?头发都白了啊!
如果使用 MQ,A 系统产生一条数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。如果新系统需要数据,直接从 MQ 里消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消费即可。这样下来,A 系统压根儿不需要去考虑要给谁发送数据,不需要维护这个代码,也不需要考虑人家是否调用成功、失败超时等情况。
总结:通过一个 MQ,Pub/Sub 发布订阅消息这么一个模型,A 系统就跟其它系统彻底解耦了。
面试技巧:你需要去考虑一下你负责的系统中是否有类似的场景,就是一个系统或者一个模块,调用了多个系统或者模块,互相之间的调用很复杂,维护起来很麻烦。但是其实这个调用是不需要直接同步调用接口的,如果用 MQ 给它异步化解耦,也是可以的,你就需要去考虑在你的项目里,是不是可以运用这个 MQ 去进行系统的解耦。在简历中体现出来这块东西,用 MQ 作解耦。
异步
再来看一个场景,A 系统接收一个请求,需要在自己本地写库,还需要在 BCD 三个系统写库,自己本地写库要 3ms,BCD 三个系统分别写库要 300ms、450ms、200ms。最终请求总延时是 3 + 300 + 450 + 200 = 953ms,接近 1s,用户感觉搞个什么东西,慢死了慢死了。用户通过浏览器发起请求,等待个 1s,这几乎是不可接受的。
一般互联网类的企业,对于用户直接的操作,一般要求是每个请求都必须在 200 ms 以内完成,对用户几乎是无感知的。
如果使用 MQ,那么 A 系统连续发送 3 条消息到 MQ 队列中,假如耗时 5ms,A 系统从接受一个请求到返回响应给用户,总时长是 3 + 5 = 8ms,对于用户而言,其实感觉上就是点个按钮,8ms 以后就直接返回了,爽!网站做得真好,真快!
削峰
每天 0:00 到 12:00,A 系统风平浪静,每秒并发请求数量就 50 个。结果每次一到 12:00 ~ 13:00 ,每秒并发请求数量突然会暴增到 5k+ 条。但是系统是直接基于 MySQL 的,大量的请求涌入 MySQL,每秒钟对 MySQL 执行约 5k 条 SQL。
一般的 MySQL,扛到每秒 2k 个请求就差不多了,如果每秒请求到 5k 的话,可能就直接把 MySQL 给打死了,导致系统崩溃,用户也就没法再使用系统了。
但是高峰期一过,到了下午的时候,就成了低峰期,可能也就 1w 的用户同时在网站上操作,每秒中的请求数量可能也就 50 个请求,对整个系统几乎没有任何的压力。
如果使用 MQ,每秒 5k 个请求写入 MQ,A 系统每秒钟最多处理 2k 个请求,因为 MySQL 每秒钟最多处理 2k 个。A 系统从 MQ 中慢慢拉取请求,每秒钟就拉取 2k 个请求,不要超过自己每秒能处理的最大请求数量就 ok,这样下来,哪怕是高峰期的时候,A 系统也绝对不会挂掉。而 MQ 每秒钟 5k 个请求进来,就 2k 个请求出去,结果就导致在中午高峰期(1 个小时),可能有几十万甚至几百万的请求积压在 MQ 中。
这个短暂的高峰期积压是 ok 的,因为高峰期过了之后,每秒钟就 50 个请求进 MQ,但是 A 系统依然会按照每秒 2k 个请求的速度在处理。所以说,只要高峰期一过,A 系统就会快速将积压的消息给解决掉。
优点上面已经说了,就是在特殊场景下有其对应的好处,解耦、异步、削峰。
缺点有以下几个:
系统可用性降低
系统引入的外部依赖越多,越容易挂掉。本来你就是 A 系统调用 BCD 三个系统的接口就好了,人 ABCD 四个系统好好的,没啥问题,你偏加个 MQ 进来,万一 MQ 挂了咋整,MQ 一挂,整套系统崩溃的,你不就完了?如何保证消息队列的高可用?
系统复杂度提高
硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已。
一致性问题
A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致了。
所以消息队列实际是一种非常复杂的架构,你引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉,做好之后,你会发现,妈呀,系统复杂度提升了一个数量级,也许是复杂了 10 倍。但是关键时刻,用,还是得用的。
ActiveMQ是由Apache出品,ActiveMQ是一个完全支持JMS1.1和JMS1.4规范的JMS Provider实现。它非常快速,只是多种语言的客户端和协议,而且可以非常容易的嵌入到企业的应用环境中,并有许多高级功能。
主要特性
部署环境
ActiveMQ 可以运行在 Java 语言所支持的平台之上。使用 ActiveMQ 需要:
优点
缺点
RabbitMQ 于 2007 年发布,是一个在 AMQP (高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的消息中间件之一。
主要特性
部署环境
RabbitMQ 可以运行在 Erlang 语言所支持的平台之上,包括 Solaris,BSD,Linux,MacOSX,TRU64,Windows 等。使用 RabbitMQ 需要:
优点
缺点
RocketMQ出自阿里的开源产品,用Java语言实现,在设计时参考了Kafka,并做出了自己的一些改进,消息可靠性上比Kafka更好。RocketMQ在阿里内部被广泛应用在订单,交易,充值,流计算,消息推送,日志流式处理,binglog分发等场景。
主要特性
部署环境
RocketMQ可以运行在Java语言所支持的平台之上。使用RocketMQ需要:
优点
缺点
Apache Kafka 是一个 分布式消息发布订阅 系统。它最初由 LinkedIn 公司基于独特的设计实现为一个 分布式的日志提交系统 (a distributed commit log),之后成为 Apache 项目的一部分。Kafka 性能高效、可扩展良好 并且 可持久化。它的 分区特性,可复制 和 可容错 都是其不错的特性。
主要特性
部署环境
使用 Kafka 需要:
优点
缺点
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
单机吞吐量 | 万级,比 RocketMQ、Kafka 低一个数量级 | 同 ActiveMQ | 10 万级,支撑高吞吐 | 10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
topic 数量对吞吐量的影响 | topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic | topic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源 | ||
时效性 | ms 级 | 微秒级,这是 RabbitMQ 的一大特点,延迟最低 | ms 级 | 延迟在 ms 级以内 |
可用性 | 高,基于主从架构实现高可用 | 同 ActiveMQ | 非常高,分布式架构 | 非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
消息可靠性 | 有较低的概率丢失数据 | 基本不丢 | 经过参数优化配置,可以做到 0 丢失 | 同 RocketMQ |
功能支持 | MQ 领域的功能极其完备 | 基于 erlang 开发,并发能力很强,性能极好,延时很低 | MQ 功能较为完善,还是分布式的,扩展性好 | 功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用 |
综上,各种对比之后,有如下建议:
一般的业务系统要引入 MQ,最早大家都用 ActiveMQ,但是现在确实大家用的不多了,没经过大规模吞吐量场景的验证,社区也不是很活跃,所以大家还是算了吧,我个人不推荐用这个了;
后来大家开始用 RabbitMQ,但是确实 erlang 语言阻止了大量的 Java 工程师去深入研究和掌控它,对公司而言,几乎处于不可控的状态,但是确实人家是开源的,比较稳定的支持,活跃度也高;
不过现在确实越来越多的公司会去用 RocketMQ,确实很不错,毕竟是阿里出品,但社区可能有突然黄掉的风险(目前 RocketMQ 已捐给 Apache,但 GitHub 上的活跃度其实不算高)对自己公司技术实力有绝对自信的,推荐用 RocketMQ,否则回去老老实实用 RabbitMQ 吧,人家有活跃的开源社区,绝对不会黄。
所以中小型公司,技术实力较为一般,技术挑战不是特别高,用 RabbitMQ 是不错的选择;大型公司,基础架构研发实力较强,用 RocketMQ 是很好的选择。
如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。
为什么以及何时在您的物联网项目中使用消息队列?
考虑温室中的温度传感器,它测量温度。您的应用程序可以在15分钟的时间间隔内(每天月96次)将温度发送到消息队列。而不是处理温室中的数据并始终连接。
物联网的消息队列旨在提供轻量级的发布/订阅消息传输。您只需发送数据并在另一项服务中处理数据,而不是保留处理温室数据的应用程序。这需要较少的网络带宽,这可能会限制您的传感器,或者您的传感器通过卫星链路进行通信。
消息队列使您的应用程序具有低功耗,发送最小化的数据包,并有效地将信息分发给一个或多个接收器。
消息队列是一种服务到服务通信的方式。它允许应用程序通过相互发送消息进行通信。消息队列的基本体系结构很简单,有些客户端应用程序可以创建消息并将它们传递到消息队列。其他应用程序/服务从队列中检索消息并处理消息中包含的请求和信息
消息可以包含任何类型的信息。例如,它可以获得有关应该从另一个应用程序(可能位于其他位置)开始的进程/任务的消息,或者它可能只是需要处理的数据。
因特网 应用程序被动反应和异步是一个“必须”。大多数IoT应用程序应该能够处理来自设备的许多连接以及从中过去的所有消息
异步消息传递在机器到机器通信中被广泛使用。这以为这发送方不会期望立即相应,并且发送方在等待相应是时不会“阻止”任何内容。
异步通信可以实现灵活性,应用程序可以发送消息,然后继续处理其他事情-在同步通信中,它必须等待实时响应。您可以将消息写入队列,然后让相同的业务员逻辑发生,而不是调用Web服务并等待它完成。
在您的应用程序需要完成某些操作但不需要立即完成,或者甚至不关心结果的情况下,队列可能很棒。
消息队列可用于实现解耦,并有助于保持结构的灵活性。它使得用不同语言编写的两个不同的应用程序连接在一起非常容易。
消息队列允许每个组件独立地执行其任务-它允许组件保持完全自治并且彼此不知道,一项服务的更改不应要求更改其他服务。它是分离服务的过程因此它们的功能更加独立。
应用程序有时会崩溃 - 它会发生。这可能是由于超时或您的代码中只有错误影响整个应用程序。消息队列强制可以使接收应用程序确认它已完成任务,并且可以安全地从队列中删除该任务。如果接收应用程序中的任何内容失败,该消息将保留在队列中。
当目标程序繁忙或未连接时,消息队列提供临时消息存储。
通过打破您的应用程序并按队列分隔不同的组件,您固有地创建了更多的弹性。即使部分后端处理延迟,您的应用程序仍然可以运行。
许多应用程序的流量激增。门铃应用程序,让您可以从任何地方回答您的门,万圣节期间可能会有交通高峰,而购物应用程序可能会在黑色星期五有交通高峰。通过对数据进行排队,您可以确保最终保留和处理您的数据; 即使这意味着由于高流量峰值,它需要比平常更长的时间。
------------------------------------------------------------------------------------------------------------------------------
如果您觉得这篇博客对您有帮助,希望您能略微打赏打赏。如果您有业务合作意向,请私信联系。