白话讲解:消息队列到底解决了什么问题?
2020年处于移动互联网的下半场,各种技术层出不穷,虽然数据也在爆发式增长,但是高并发、高吞吐已经不再是首要的痛点,稳定、可靠才是王道。
本文作为一篇消息队列入门级介绍,帮助大家对消息队列有一个大致的了解,并对对时下流行的消息队列组件进行了简单的比较,供大家做技术选型的参考。
1 什么是消息队列
消息队列(Message Queue),从广义上讲是一种消息队列服务中间件,提供一套完整的信息生产、传递、消费的软件系统。
消息队列所涵盖的功能远不止于队列(Queue),其本质是两个进程传递信息的一种方法。两个进程可以分布在同一台机器上,亦可以分布在不同的机器上。
众所周知,进程通信可以通过RPC(Remote Procedure Call,远程过程调用)进行,那么我们为什么要用消息队列这种软件服务来传递消息呢?
下面我们以春节订火车票为例进行说明,流程如下。
拿到年终奖了,准备买车票带着媳妇儿回家过年。你打开12306手机App开始做如下操作:
第一步:输入车票信息,发送订票请求。
起点站:北京。
终点站:成都。
出发时间:腊月29晚上8点。
票数:2张。
座席:硬卧。
第二步:单击“预订”按钮,12306 App界面开始转圈圈。与此同时全国3亿人民也在和你一起做相同的事情。
第三步:3s后,应用告诉你订票失败。
第四步:你修改车次,重新发送订票请求。应用重复第二步继续等待。又一个3s后,12306 App告诉你订票成功。
12306 App在处理上图逻辑时,会遇到以下挑战:
(1)今天这个车次只售出4000张票,而实际有30万人发送了订票信息,如果逐一请求处理,那么90%以上的人都将要耗时3s来等待,怎么办?
(2)下游有20个系统需要在订票成功后进行通知,如果逐一调用这些系统的接口进行通知,而其中一个通知任务执行失败,那么已经通知成功的任务会怎样?
(3)12306 App架构会不断调整,当数据结构发生变化时,下游20个系统都随着一起变化吗?
以上只是随机列举了一些常见的问题,如何才能优雅地处理呢?
答案是:消息队列!
2 为什么需要消息队列
我们平时什么时候可能会用到消息队列呢?下面结合刚才的流程图来介绍消息队列的适用场景。
▊ 削峰填谷
业务系统在超高并发场景中,由于后端服务来不及同步处理过多、过快的请求,可能导致请求堵塞,严重时可能由于高负荷拖垮Web服务器。
我们都希望流量如上图虚线部分一样一直比较平稳,这样我们的系统也会更加稳定。但是实际的流量会随着时间不短变化,像12306 App这样的App流量大得难以想象,而一年中不同的时间段,其流量也不同。为了能支持最高峰流量,我们通常采取短平快的方式——直接扩容服务器,增加服务端的吞吐量。
优点是显而易见的,短时间内吞吐量增加了好几倍,甚至数十倍。缺点也明显,流量低峰期服务器相对较闲。
如何平衡平时的空闲与节假日的超高峰呢?我们想到了消息队列(比如Apache RocketMQ,Apache Kafka),也是目前业界比较常用的手段。利用消息队列扭转处理订票请求,告知用户30min内会告诉他/她订票结果。优缺点明显:性能提升了,但是我们作为业务开发人员,还要维护一个消息队列服务,人手完全不够。消息中间件呼之欲出。
▊ 程序间解耦
不同的业务端在联合开发功能时,常常由于排期不同、人员调配不方便等原因导致项目延期。其实,其根本原因是业务耦合过度。
下图中,上下游系统之间的通信是彼此依赖的,所以不得不协调上下游所有的资源同步进行,跨团队处理问题显然比在团队内部处理问题难度大。
你是否依稀记得另一个团队的同事调用你的API,你告诉他发个请求过来,你打断点一步一步调试代码的场景?
你是否记得为了协调开发资源、QA资源,以及协调上线时间等所做的一切,你被老板骂了多少次,最后还是延期了:我们依赖他们,他们的QA说,高峰期不让发布。
加入消息队列后,不同的业务端又会是何种情况呢?
上下游系统进行开发、联调、上线,彼此完全不依赖,也就是说,系统间解耦了。
▊ 异步处理
处理订票请求是一个漫长的过程,需要检查预订的车次是否有预订数量的票、下单扣库存、更新缓存等一系列操作。这些耗时的操作,我们可以通过使用消息队列的方式,把提交请求成功的消息告诉用户。然后异步处理这些耗时的操作,保证30min内能把处理的结果通过短信推送给用户,否则系统处理多久,用户就会等多久。
▊ 数据的最终一致性
我们举例说明。很怀念每月的1号,可以向老婆的“财务部”缴费了。你的工资在招商银行,你老婆的工资在北京银行。通常,两个系统的通信过程如下。
如果通信失败,怎么保证你的钱“上交”了呢?业内常用的手段就是消息队列。消息系统的优点:
(1)免去了招商银行App多次重试(发起请求)的复杂逻辑。(2)免去了北京银行App处理过多重试请求的压力。(3)即使北京银行服务不可用,业务也不受影响。
3 常见消息队列
这里对时下流行的消息队列组件进行了简单的比较,供大家做技术选型的参考。
消息队列名字 | Apache ActiveMQ | Apache Kafka | Apache RocketMQ | Apahe Pulsar |
产生时间 | 2007 | 2012 | 2017 | 2018 |
贡献公司 | Apache | 阿里巴巴 | 雅虎 | |
当时流行MQ | JMS | ActiveMQ | Kafka,ActiveMQ | RocketMQ,Kafka |
特性 | (1)支持协议众多:AMQP,STOMP,MQTT,JMS (2)消息是持久化的JDBC | (1)超高写入速率 (2)end-to-end耗时毫秒级 | (1)万亿级消息支持 (2)万级Topic数量支持 (3)end-to-end耗时毫秒级 | (1)存储计算分离 (2)支持SQL数据查询 |
管理后台 | 自带 | 独立部署 | 独立部署 | 无 |
多语言客户端 | 支持 | 支持 | Java C++ Python Go C# | Java C++ Python Go |
数据流支持 | 不支持 | 支持 | 支持 | 支持 |
消息丢失 | 理论上不会丢失 | 理论上不会丢失 | 理论上不会丢失 | 理论上不会丢失 |
文档完备性 | 好 | 极好 | 极好 | 社区不断完善中 |
商业公司实践 | 国内部分企业 | 阿里巴巴 | 雅虎、腾讯、智联招聘 | |
容错 | 无重试机制 | 无重试机制 | 支持重试,死信消息 | 支持重试、死信消息 |
顺序消息 | 支持 | 支持 | 支持 | 支持 |
定时消息 | 不支持 | 不支持 | 支持 | 支持 |
事务消息 | 不支持 | 支持 | 支持 | 支持 |
消息轨迹 | 不支持 | 不支持 | 支持 | 自己实现简单 |
消息查询 | 数据库中查询 | 不支持 | 支持 | 支持SQL |
重放消息 | 不清楚 | 暂停重放 | 实时重放 | 支持 |
宕机 | 自动切换 | 自动选主 | 手动重启 | 自动切换 |
Apache RocketMQ是一款开源的、分布式的消息投递与流数据平台。出生自阿里巴巴,经历了近十年双11核心交易链路打磨,可以支撑万亿级消息洪峰。
作为Apache顶级开源项目之一,其在GitHub上有10000+ star、5000+ fork、170+ contributors(在GitHub上提交代码并被采纳的开发者),目前中国互联网、金融等行业Top级企业75%以上都在使用,已经成为云原生时代企业上云的核心基础设施!
学习掌握Apache RocketMQ,博文菌强烈推荐《RocketMQ分布式消息中间件:核心原理与最佳实践》一书。
作者有多年分布式系统的实战经验,特别是在消息队列方面经验丰富。本书根据作者在项目中使用RocketMQ的实际经验,结合实际源码,由浅入深地讲解了RocketMQ核心功能的具体实现逻辑,并从消息队列的应用场景出发,使读者快速地了解MQ解决的问题域。
通过阅读本书,不仅可以了解如何在项目中使用消息队列,还能学习到RocketMQ的实现细节,进一步提升对RocketMQ系统本身的把控力度。
▼扫码了解本书详情▼热文推荐