关于后端:消息队列选型

2次阅读

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

音讯队列选型

大家好,我是易安!明天咱们聊下音讯队列常见选型。

音讯队列作用

谈选型之前咱们先讲下咱们为什么须要音讯队列。

音讯队列是一种很风行的技术,自从零碎间开始通信时,音讯队列就呈现了。然而,对音讯队列给出一个准确的定义却颇为艰难。咱们晓得,音讯队列的外围性能是收发音讯,但它的作用远不止于解决利用间通信问题这么简略。

让咱们通过一个例子来论述音讯队列的作用。假如小明领有一家巧克力工厂,制作美味巧克力须要经验三个阶段:首先将可可豆研磨成可可粉,接着把可可粉加热并退出糖制成巧克力浆,最初将巧克力浆倒入模具,撒上碎坚果,通过冷却便成为巧克力产品。

起初,工人们在研磨出一桶可可粉后,便将其送至下一阶段的工人手中,而后回去持续研磨。小明很快意识到,其实工人不用亲自运送半成品。于是,他在各个阶段之间设置了传送带,使得工人只需将研磨好的可可粉放在传送带上,便可持续解决下一批可可豆。传送带解决了不同阶段工序间的“通信”问题。

只管传送带进步了生产效率,但也带来了新的问题:各个阶段的生产速度并不统一。当一桶可可粉传送至巧克力浆车间时,工人可能正在解决上一批可可粉,无奈立刻接管。各个阶段的工人须要协调何时将半成品搁置在传送带上。如果上下游阶段处理速度不匹配,工人须要相互期待,确保传送带上的半成品不被脱漏。

为解决这一问题,小明在每组传送带的上游设置了一个暂存半成品的仓库。这样一来,上游工人无需期待上游工人,随时可将解决好的半成品搁置在传送带上。无奈及时接管的半成品将暂存在仓库中,供上游工人随时取用。这些仓库实际上在“通信”过程中施展了“缓存”的作用。

传送带解决了半成品运输问题,仓库能够暂存一些半成品,解决了上下游生产速度不统一的问题,小明在人不知; 鬼不觉中实现了一个巧克力工厂版的音讯队列。

音讯队列应用场景

咱们日常开发中,哪些问题适宜应用音讯队列解决呢?

1. 异步解决

大多数程序员在面试中,应该都问过或被问过一个经典却没有标准答案的问题:如何设计一个秒杀零碎?这个问题能够有一百个版本的正当答案,但大多数答案中都离不开音讯队列。

秒杀零碎须要解决的外围问题是,如何利用无限的服务器资源,尽可能多地解决短时间内的海量申请。咱们晓得,解决一个秒杀申请蕴含了很多步骤,例如:

  • 危险管制;
  • 库存锁定;
  • 生成订单;
  • 短信告诉;
  • 更新统计数据。

如果没有任何优化,失常的解决流程是:App 将申请发送给网关,顺次调用上述 5 个流程,而后将后果返回给 APP。

对于这 5 个步骤来说,是否决定秒杀胜利,实际上只有危险管制和库存锁定这 2 个步骤。只有用户的秒杀申请通过危险管制,并在服务端实现库存锁定,就能够给用户返回秒杀后果了,对于后续的生成订单、短信告诉和更新统计数据等步骤,并不一定要在秒杀申请中解决实现。

所以当服务端实现后面 2 个步骤,确定本次申请的秒杀后果后,就能够马上给用户返回响应,而后把申请的数据放入音讯队列中,由音讯队列异步地进行后续的操作。

解决一个秒杀申请,从 5 个步骤缩小为 2 个步骤,这样不仅响应速度更快,并且在秒杀期间,咱们能够把大量的服务器资源用来解决秒杀申请。秒杀完结后再把资源用于解决前面的步骤,充分利用无限的服务器资源解决更多的秒杀申请。

能够看到,在这个场景中,音讯队列被用于实现服务的异步解决。 这样做的益处是:

  • 能够更快地返回后果;
  • 缩小期待,天然实现了步骤之间的并发,晋升零碎总体的性能。
2. 流量管制

持续说咱们的秒杀零碎,咱们曾经应用音讯队列实现了局部工作的异步解决,但咱们还面临一个问题:如何防止过多的申请压垮咱们的秒杀零碎?

一个设计强壮的程序有自我爱护的能力,也就是说,它应该能够在海量的申请下,还能在本身能力范畴内尽可能多地解决申请,回绝解决不了的申请并且保障本身运行失常。可怜的是,事实中很多程序并没有那么“强壮”,而间接拒绝请求返回谬误对于用户来说也是不怎么好的体验。

因而,咱们须要设计一套足够强壮的架构来将后端的服务爱护起来。 咱们的设计思路是,应用音讯队列隔离网关和后端服务,以达到流量管制和爱护后端服务的目标。

退出音讯队列后,整个秒杀流程变为:

  1. 网关在收到申请后,将申请放入申请音讯队列;
  2. 后端服务从申请音讯队列中获取 APP 申请,实现后续秒杀处理过程,而后返回后果。

秒杀开始后,当短时间内大量的秒杀申请达到网关时,不会间接冲击到后端的秒杀服务,而是先沉积在音讯队列中,后端服务依照本人的最大解决能力,从音讯队列中生产申请进行解决。

对于超时的申请能够间接抛弃,APP 将超时无响应的申请解决为秒杀失败即可。运维人员还能够随时减少秒杀服务的实例数量进行程度扩容,而不必对系统的其余局部做任何更改。

这种设计的长处是:能依据上游的解决能力主动调节流量,达到“削峰填谷”的作用。但这样做同样是有代价的:

  • 减少了零碎调用链环节,导致总体的响应时延变长。
  • 上下游零碎都要将同步调用改为异步音讯,减少了零碎的复杂度。

那还有没有更简略一点儿的流量管制办法呢?如果咱们能预估出秒杀服务的解决能力,就能够用音讯队列实现一个令牌桶,更简略地进行流量管制。

令牌桶管制流量的原理是:单位工夫内只发放固定数量的令牌到令牌桶中,规定服务在解决申请之前必须先从令牌桶中拿出一个令牌,如果令牌桶中没有令牌,则拒绝请求。这样就保障单位工夫内,能解决的申请不超过发放令牌的数量,起到了流量管制的作用。

实现的形式也很简略,不须要毁坏原有的调用链,只有网关在解决 APP 申请时减少一个获取令牌的逻辑。

令牌桶能够简略地用一个有固定容量的音讯队列加一个“令牌发生器”来实现:令牌发生器依照预估的解决能力,匀速生产令牌并放入令牌队列(如果队列满了则抛弃令牌),网关在收到申请时去令牌队列生产一个令牌,获取到令牌则持续调用后端秒杀服务,如果获取不到令牌则间接返回秒杀失败。

以上是罕用的应用音讯队列两种进行流量管制的设计办法,你能够依据各自的优缺点和不同的实用场景进行正当抉择。

3. 服务解耦

音讯队列的另外一个作用,就是实现零碎利用之间的解耦。再举一个电商的例子来阐明解耦的作用和必要性。

咱们晓得订单是电商零碎中比拟外围的数据,当一个新订单创立时:

  1. 领取零碎须要发动领取流程;
  2. 风控系统须要审核订单的合法性;
  3. 客服零碎须要给用户发短信告知用户;
  4. 经营剖析零碎须要更新统计数据;

这些订单上游的零碎都须要实时取得订单数据。随着业务一直倒退,这些订单上游零碎一直的减少,一直变动,并且每个零碎可能只须要订单数据的一个子集,负责订单服务的开发团队不得不破费很大的精力,应答一直减少变动的上游零碎,不停地批改调试订单零碎与这些上游零碎的接口。任何一个上游零碎接口变更,都须要订单模块从新进行一次上线,对于一个电商的外围服务来说,这简直是不可承受的。

所有的电商都抉择用音讯队列来解决相似的零碎耦合过于严密的问题。引入音讯队列后,订单服务在订单变动时发送一条音讯到音讯队列的一个主题 Order 中,所有上游零碎都订阅主题 Order,这样每个上游零碎都能够取得一份实时残缺的订单数据。

无论减少、缩小上游零碎或是上游零碎需要如何变动,订单服务都无需做任何更改,实现了订单服务与上游服务的解耦。

上述,咱们介绍了音讯队列的三种应用场景:异步解决、流量管制和服务解耦。当然,音讯队列的适用范围不仅仅局限于这些场景,还有包含:

  • 作为公布 / 订阅零碎实现一个微服务级零碎间的观察者模式;
  • 连贯流计算工作和数据;
  • 用于将音讯播送给大量接收者。

简略的说,咱们在单体利用外面须要用队列解决的问题,在分布式系统中大多都能够用音讯队列来解决。

同时咱们也要意识到,音讯队列也有它本身的一些问题和局限性,包含:

  • 引入音讯队列带来的提早问题;
  • 减少了零碎的复杂度;
  • 可能产生数据不统一的问题。

所以咱们说没有最好的架构,只有最适宜的架构,依据指标业务的特点和本身条件抉择适合的架构,才是体现一个架构师功力的中央。

在音讯队列的技术选型这个问题上,也是同样的情理。并不存在说,哪个音讯队列就是“最好的”。罕用的这几个音讯队列,每一个产品都有本人的劣势和劣势,你须要依据现有零碎的状况,抉择最适宜你的那款产品,那么咱们如何来抉择音讯队列呢?

选型准则

尽管这些音讯队列产品在性能和个性方面各有优劣,但咱们在抉择的时候要有一个根本准则,保障入选的产品至多是及格的。

接下来咱们先说一下这及格的规范是什么样的。

首先,必须是开源的产品,这个十分重要。开源意味着,如果有一天你应用的音讯队列遇到了一个影响你零碎业务的 Bug,你至多还有机会通过批改源代码来迅速修复或躲避这个 Bug,解决你的零碎迫在眉睫的问题,而不是大刀阔斧地期待开发者不肯定什么时候公布的下一个版本来解决。

其次,这个产品必须是近年来比拟风行并且有肯定社区活跃度的产品。风行的益处是,只有你的应用场景不太冷门,你遇到 Bug 的概率会非常低,因为大部分你可能遇到的 Bug,其他人早就遇到并且修复了。你在应用过程中遇到的一些问题,也比拟容易在网上搜寻到相似的问题,而后很快的找到解决方案。

还有一个劣势就是,风行的产品与周边生态系统会有一个比拟好的集成和兼容,比方,Kafka 和 Flink 就有比拟好的兼容性,Flink 内置了 Kafka 的 Data Source,应用 Kafka 就很容易作为 Flink 的数据源开发流计算利用,如果你用一个比拟小众的音讯队列产品,在进行流计算的时候,你就不得不本人开发一个 Flink 的 Data Source。

最初,作为一款及格的音讯队列产品,必须具备的几个个性包含:

  • 音讯的牢靠传递:确保不丢音讯;
  • Cluster:反对集群,确保不会因为某个节点宕机导致服务不可用,当然也不能丢音讯;
  • 性能:具备足够好的性能,能满足绝大多数场景的性能要求。

接下来咱们一起看一下有哪些合乎下面这些条件,可供选择的开源音讯队列产品。

主流产品

1. RabbitMQ

首先,咱们说一下老牌儿音讯队列 RabbitMQ。RabbitMQ 是应用一种比拟小众的编程语言:Erlang 语言编写的,它最早是为电信行业零碎之间的牢靠通信设计的,也是少数几个反对 AMQP 协定的音讯队列之一。

RabbitMQ 就像它的名字中的兔子一样:轻量级、迅捷,它的 Slogan,也就是宣传口号,也很明确地表明了 RabbitMQ 的特点:Messaging that just works,“开箱即用的音讯队列”。也就是说,RabbitMQ 是一个相当轻量级的音讯队列,非常容易部署和应用。

另外 RabbitMQ 还号称是世界上应用最宽泛的开源音讯队列,是不是真的使用率世界第一,咱们没有方法统计,但至多是“最风行的音讯两头之一”,这是没有问题的。

RabbitMQ 一个比拟有特色的性能是反对非常灵活的路由配置,和其余音讯队列不同的是,它在生产者(Producer)和队列(Queue)之间减少了一个 Exchange 模块,你能够了解为交换机。

这个 Exchange 模块的作用和交换机也十分类似,依据配置的路由规定将生产者收回的音讯散发到不同的队列中。路由的规定也非常灵活,甚至你能够本人来实现路由规定。基于这个 Exchange,能够产生很多的玩儿法,如果你正好须要这个性能,RabbitMQ 是个不错的抉择。

RabbitMQ 的客户端反对的编程语言大略是所有音讯队列中最多的,如果你的零碎是用某种冷门语言开发的,那你多半能够找到对应的 RabbitMQ 客户端。

接下来说下 RabbitMQ 的几个问题。

  • RabbitMQ 对音讯沉积的反对并不好,在它的设计理念外面,音讯队列是一个管道,大量的音讯积压是一种不失常的状况,该当尽量去防止。当大量音讯积压的时候,会导致 RabbitMQ 的性能急剧下降。
  • RabbitMQ 的性能是我介绍的这几个音讯队列中最差的,依据官网给出的测试数据综合咱们日常应用的教训,根据硬件配置的不同,它大略每秒钟能够解决几万到十几万条音讯。其实,这个性能也足够撑持绝大多数的利用场景了,不过,如果你的利用对音讯队列的性能要求十分高,那不要抉择 RabbitMQ。
  • RabbitMQ 应用的编程语言 Erlang,这个编程语言不仅是十分小众的语言,更麻烦的是,这个语言的学习曲线十分平缓。大多数风行的编程语言,比方 Java、C/C++、Python 和 JavaScript,尽管语法、个性有很多的不同,但它们根本的体系结构都是一样的,你只精通一种语言,也很容易学习其余的语言,短时间内即便做不到精通,但至多能达到“会用”的程度。就像一个以英语为母语的人,学习法语、德语都很容易,然而你要是让他去学汉语,那基本上和学习其余这些语言不是一个难度级别的。很可怜的是,Erlang 就是编程语言中的“汉语”。所以如果你想基于 RabbitMQ 做一些扩大和二次开发什么的,倡议你慎重考虑一下可继续保护的问题。

2. RocketMQ

RocketMQ 是阿里巴巴在 2012 年开源的音讯队列产品,起初捐献给 Apache 软件基金会,2017 正式毕业,成为 Apache 的顶级我的项目。阿里外部也是应用 RocketMQ 作为撑持其业务的音讯队列,经验过屡次“双十一”考验,它的性能、稳定性和可靠性都是值得信赖的。作为优良的国产音讯队列,近年来越来越多的被国内泛滥大厂应用。

我在总结 RocketMQ 的特点时,发现很难找出 RocketMQ 有什么特地让我印象粗浅的特点,也很难找到它有什么毛病。

RocketMQ 就像一个品学兼优的好学生,有着不错的性能,稳定性和可靠性,具备一个古代的音讯队列应该有的简直全副性能和个性,并且它还在继续的成长中。

RocketMQ 有十分沉闷的中文社区,大多数问题你都能够找到中文的答案,兴许会成为你抉择它的一个起因。另外,RocketMQ 应用 Java 语言开发,它的贡献者大多数都是中国人,源代码绝对也比拟容易读懂,你很容易对 RocketMQ 进行扩大或者二次开发。

RocketMQ 对在线业务的响应时延做了很多的优化,大多数状况下能够做到毫秒级的响应, 如果你的利用场景很在意响应时延,那应该抉择应用 RocketMQ。

RocketMQ 的性能比 RabbitMQ 要高一个数量级,每秒钟大略能解决几十万条音讯。

RocketMQ 的一个劣势是,作为国产的音讯队列,相比国外的比拟风行的同类产品,在国内上还没有那么风行,与周边生态系统的集成和兼容水平要略逊一筹。

3. Kafka

最初咱们聊一聊 Kafka。Kafka 最早是由 LinkedIn 开发,目前也是 Apache 的顶级我的项目。Kafka 最后的设计目标是用于解决海量的日志。

在晚期的版本中,为了取得极致的性能,在设计方面做了很多的就义,比方不保障音讯的可靠性,可能会失落音讯,也不反对集群,性能上也比拟简陋,这些就义对于解决海量日志这个特定的场景都是能够承受的。这个期间的 Kafka 甚至不能称之为一个合格的音讯队列。

然而,请留神,重点个别都在前面。随后的几年 Kafka 逐渐补齐了这些短板,你在网上搜到的很多音讯队列的比照文章还在说 Kafka 不牢靠,其实这种说法早已通过时了。当下的 Kafka 曾经倒退为一个十分成熟的音讯队列产品,无论在数据可靠性、稳定性和性能个性等方面都能够满足绝大多数场景的需要。

Kafka 与周边生态系统的兼容性是最好的没有之一,尤其在大数据和流计算畛域,简直所有的相干开源软件系统都会优先反对 Kafka。

Kafka 应用 Scala 和 Java 语言开发,设计上大量应用了批量和异步的思维,这种设计使得 Kafka 能做到超高的性能。Kafka 的性能,尤其是异步收发的性能,是三者中最好的,但与 RocketMQ 并没有量级上的差别,大概每秒钟能够解决几十万条音讯。

我已经应用配置比拟好的服务器对 Kafka 进行过压测,在有足够的客户端并发进行异步批量发送,并且开启压缩的状况下,Kafka 的极限解决能力能够超过每秒 2000 万条音讯。

然而 Kafka 这种异步批量的设计带来的问题是,它的同步收发音讯的响应时延比拟高,因为当客户端发送一条音讯的时候,Kafka 并不会立刻发送进来,而是要等一会儿攒一批再发送,当然你也能够配置依照工夫拉取。当你的业务场景中,每秒钟音讯数量没有那么多的时候,Kafka 的时延反而会比拟高。所以,Kafka 不太适宜在线业务场景。

其余产品

除了下面给你介绍的三大音讯队列之外,还有几个产品,我集体的观点是,这些产品之所以没那么风行,或多或少都有着比拟显著的短板,不举荐应用。在这儿呢,我简略介绍一下,纯当丰盛你的常识广度。

先说 ActiveMQ,ActiveMQ 是最老牌的开源音讯队列,是十年前惟一可供选择的开源音讯队列,目前已进入老年期,社区不沉闷。无论是性能还是性能方面,ActiveMQ 都与古代的音讯队列存在显著的差距,它存在的意义仅限于兼容那些还在用的爷爷辈儿的零碎。

接下来说说 ZeroMQ,严格来说 ZeroMQ 并不能称之为一个音讯队列,而是一个基于音讯队列的多线程网络库,如果你的需要是将音讯队列的性能集成到你的零碎过程中,能够思考应用 ZeroMQ。

最初说一下 Pulsar,很多人可能都没听说过这个产品,Pulsar 是一个新兴的开源音讯队列产品,最早是由 Yahoo 开发,目前处于成长期,风行度和成熟度绝对没有那么高。与其余音讯队列最大的不同是,Pulsar 采纳存储和计算拆散的设计,官网号称延时远低于 kafka,然而吞吐量超出 kafka 很多,当然这个统计的形式有待商讨,有趣味前面我会出文章剖析下。

总结

在理解了下面这些开源音讯队列各自的特点和优劣势后,我置信你对于音讯队列的抉择曾经能够做到成竹在胸了。我也总结了几条抉择的倡议供你参考。

如果说,音讯队列并不是你将要构建零碎的配角之一,你对音讯队列性能和性能都没有很高的要求,只须要一个开箱即用易于保护的产品,我倡议你应用 RabbitMQ。

如果你的零碎应用音讯队列次要场景是解决在线业务,比方在交易系统中用音讯队列传递订单,那 RocketMQ 的低提早和金融级的稳定性是你须要的。

如果你须要解决海量的音讯,像收集日志、监控信息或是前端的埋点这类数据,或是你的利用场景大量应用了大数据、流计算相干的开源产品,那 Kafka 是最适宜你的音讯队列。

如果我说的这些场景和你的场景都不合乎,你看了我之前介绍的这些音讯队列的特点后,还是不晓得如何抉择,那就选你最相熟的吧。

如果本文对你有帮忙的话,欢送点赞分享,这对我持续分享 & 创作优质文章十分重要。感激!

本文由 mdnice 多平台公布

正文完
 0