一、简介
消息队列大家应该不陌生,没接触过的可以先看下我的另一个专栏分布式消息中间件系列。目前常见的开源分布式消息队列主要有下面几种:
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
单机吞吐量 | 万级 | 万级 | 10万级 | 10万级以上 |
topic数量 | / | / | topic达到千级时,吞吐量会小幅下降 | topic达到百级时,吞吐量会大幅下降 |
时效性 | 毫秒级 | 微秒级 | 毫秒级 | 毫秒级 |
可用性 | 高,主从架构 | 高,主从架构 | 非常高,数据分散集群架构 | 极高,数据分散集群架构 |
消息可靠性 | 有较低的概率丢失数据 | 有较低的概率丢失数据 | 经过参数配置,可以做到0丢失 | 经过参数配置,可以做到0丢失 |
框架开发语言 | Java | erlang | Java | Java |
优劣势 | 优势:非常成熟,功能完备,在业内大量的公司以及项目中都有应用;劣势:社区不活跃,版本迭代很慢,不适合大规模并发场景。 | 优势:自带管理界面非常好用,社区活跃,版本迭代快;劣势:吞吐量一般,erlang不利于研究源码。 | 优势:吞吐量非常高,适合大规模高并发应用,功能丰富,社区活跃;劣势:依赖阿里,一旦被抛弃,后续维护有风险 | 优势:吞吐量极高,可用性极高,社区活跃适合大规模高并发应用,社区活跃,适合大数据实时计算以及日志收集劣势:功能较单一 |
我们后续会针对RabbitMQ、RocketMQ、Kalfka这三种主流MQ作讲解,本章我们先来看下为什么要在我们的系统中引入分布式消息队列?
我们在自己的系统中引入消息队列,无非就是三个目的: 解耦 、 异步 、 削峰 。本文我们就通过三个示例来讲解下消息队列的这三项基本功能。
二、解耦
在分布式系统中,解耦的目的就是降低服务之间的直接依赖。我们来看下面这个系统。
2.1 解耦前
服务A是一个供数系统,会产生一些比较关键的数据,然后通过接口调用的方式把数据给服务B和服务C,最开始服务B和服务C所需的数据是相同的,所以一切都没什么问题:
一段时间后,服务C要求服务A做一些更改,原来送的数据有些地方需要做变更,所以服务A要重新调用一个服务C的专用接口:
又过了一段时间,来了服务D和服务E,也要求服务A针对它们需要的数据调用定制接口,同时服务B告诉服务A,以前那个通用接口不用了,因为服务B要下线了:
这种直连的方式导致服务A跟各种各种乱七八糟的服务紧耦合在一起,同时还要考虑超时问题、是不是要做重试机制,维护服务A的童鞋估计要崩溃。
2.2 解耦后
我们来看下如何通过消息中间件解耦:
上图中,在服务A和各个服务之间加入MQ,服务A产生的数据全量仍到MQ,并约定好格式,哪个服务需要数据就自己去MQ消费,然后自己处理。服务A也不用考虑什么接口调用超时、重试之类的问题了。
三、异步
消息队列的另一个重要功能就是异步化接口调用,我们考虑这样一种场景:用户通过浏览器发起一个请求,后台服务针对请求做处理,但事实上用户并不需要立刻得到该请求的响应,因为页面有其它地方可以让用户稍后查询请求的结果。这是一种典型的异步请求场景,我们现在看下同步的情况。
3.1 同步请求
下图中,服务A本地执行一些逻辑耗时20ms,然后依次同步调用服务B、服务C、服务D的接口,由于各个依赖服务本地执行的逻辑各不相同,在加上网络开销,一个请求的耗时接近1s。
一般来说,对于互联网应用,如果是涉及与用户直接交互的,基本都要在200ms内完成,所以显然这种同步调用方式在当前业务场景下是不可取的。
3.2 异步请求
我们再来看下如何通过消息中间件将请求异步化:
上图中,假设服务A发送3个消息耗时5ms,加上自身执行逻辑耗时20ms,那么25ms就可以将结果响应给用户。至于服务B、服务C、服务D,都是异步从消息队列中获取消息然后执行本地逻辑,从而大大减小了请求耗时,提升了用户体验。
四、削峰
消息队列最后一种常用的场景,就是在高峰时间进行削峰。
4.1 削峰前
一般的应用可能是下图这样的,在非高峰期时期,系统几乎没什么压力,但是一旦遇到高峰流量,请求都直接打到数据库,MySQL一般扛个每秒2000请求差不多快到极限了,再高就可能崩溃:
4.2 削峰
峰值流量持续的时间不会很久,一般最多1小时就差不多了,我们完全可以利用MQ存储高峰期的请求,然后系统A依然以自身最大能力去消费MQ(假设每秒消费2000个请求),这样即使在高峰期,系统也不会挂掉:
因为非峰值时期的流量一般是很低的,所以对于积压的消息,会在高峰期过后被慢慢消费掉。举个例子,假设每秒MQ积压3000条消息,那么1小时积压1000万条消息,这1000万条消息基本上1个小时就可以被系统A处理完。
五、总结
引入分布式消息队列后,会给系统带来很多好处,最主要的就是性能方面,但同时也会使系统的复杂性变高。一方面,MQ自身需要做到高可用,另一方面,多个系统通过MQ进行交互,如何保证数据一致性?(比如3.2中的系统A处理完后直接返回成功,系统B、C、D中的BC写库成功,但是D失败了,这时候数据就不一致了)我们后续章节,会针对使用消息队列过程中的一些核心问题进行分析讲解。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。