消息队列比较-做出明智的选择-了解主流消息队列之间的差异 (消息队列比较好的软件)
消息队列(MQ)是历史最悠久的中间件之一,它能够与不同的进程通信,从而实现上下游之间的消息传递。基于此特性,我们可以在以下三个场景中使用消息队列:
1)解耦
假设有两个服务:A和B,当服务A依赖服务B时,请求的耗时就是这两个服务之和。但如果服务B耗时比较长怎么办?显然这时服务A可以将消息发送到队列中,服务B从队列里面去取即可,从而实现两个服务之间的逻辑解耦+物理解耦。
举个例子,当用户注册账号时,会将注册信息发给账号服务,账号服务将信息写入数据库后,会调用短信服务给用户发送短信。如果不使用消息队列,那么必须等短信发送成功之后才能返回。但为了给用户更好的体验,我们可以将发送短信这一步独立出去,账号服务将用户手机号和短信内容投入消息队列中就可以返回了,这样用户就能立刻收到注册结果。而短信服务会消费消息,异步执行发送短信逻辑,这就是消息队列的作用之一:解耦。
使用消息队列进行解耦,不仅可以提升性能,还可以使整个系统更加的模块化。以电商为例,订单服务是电商系统中的核心部分,它会被一系列下游服务依赖。并且随着业务的发展,依赖订单的下游服务会不断增加、不断变化。因此负责订单服务的开发团队不得不花费大量精力,应对不断增加变化的下游服务,不停地修改调试订单服务与这些下游服务的接口。任何一个下游服务的接口产生变更,都需要订单模块重新进行一次上线,对于一个电商的核心服务来说,这几乎是不可接受的。因此所有的电商系统都选择用消息队列,来解决这种系统耦合过于紧密的问题。
引入消息队列后,订单服务在订单变化时发送一条消息到消息队列的一个主题order中,所有下游服务都订阅主题order,这样每个下游服务都可以获得一份实时完整的订单数据。并且此时下游服务发生变化,不会影响订单服务。
2)限流
一个完善的系统一定具备自我保护的能力,即使面对海量请求,也能尽最大努力去处理,处理不了的则会拒绝掉,从而保证系统运行正常。因此如果我们能预估出系统的最大处理能力,就可以用消息队列实现一个令牌桶,进行流量控制。
令牌桶控制流量的原理是:单位时间内发放固定数量的令牌到令牌桶中,规定服务在处理请求之前必须先从桶中取走一个令牌,如果桶里面没有令牌,则拒绝请求。这样就保证单位时间内,能处理的请求数不超过发放令牌的数量,起到了流量控制的作用。
令牌桶可以简单地用一个有固定容量的消息队列加一个令牌生成器来实现:令牌生成器按照预估的处理能力,匀速生产令牌并放入令牌队列(如果队列满了则丢弃令牌)。网关(流量的入口)在收到请求时从令牌队列消费一个令牌,获取到令牌则继续调用后端服务,如果获取不到令牌则直接返回失败。
3)流量削峰
任何的大型服务,特别是秒杀服务,都离不开消息队列。因为消息队列除了解耦和限流之外,还可以起到流量削峰的作用,就是缓冲瞬时的突发流量,使其更平滑。对于那些发送能力很强的上游系统,如果没有消息队列的保护,脆弱的下游系统可能会直接被压垮导致全链路服务雪崩。而一旦有了消息队列,它就能够有效地对抗上游的流量冲击,避免了流量的震荡。
我们举一个实际的例子,比如在京东购买商品,当点击购买的时候,会调用订单服务生成对应的订单。然而要处理该订单则会依次调用下游的多个子服务,比如查询登录信息、验证商品信息、确认地址信息,调用银行等支付接口进行扣款等等。显然上游的订单操作比较简单,它的TPS要远高于处理订单的下游服务。因此如果上游和下游直接对接,势必会出现下游服务无法及时处理上游订单从而造成订单堆积的情况。特别是当出现双十一以及秒杀业务的时候,上游订单流量会瞬间增加,可能出现的结果就是直接压垮下游子系统服务。
解决此问题的一个做法是对上游的订单服务进行限流,比如采用上面说的令牌桶。但对于一个电商系统来说,这么做很明显是不合适的,因为问题不是出现在订单服务上面,而且用户买东西的时候最关心的是订单能不能创建成功,而不是什么时候能创建成功。因此使用消息队列来削峰是一个更好的选择:用户下单时,订单服务将信息放入消息队列后就认为订单创建成功,然后立即返回。而后续复杂的业务处理可以异步进行,这样既保证了上游订单创建的吞吐量,又防止了下游服务被压垮。
结论
消息队列在现代系统设计中是一个非常重要的组件,它可以用来解决许多常见的系统问题,如解耦、限流和流量削峰。使用消息队列可以显著提高系统的性能、可靠性和可扩展性。
Kafka还是RabbitMQ?
现在的系统已经离不开消息队列,我们可以用他做异步,做解耦,做流处理,做可靠传输。 市面上的消息队列也有很多,比如阿里云的oss,RocketMQ,ZeroMQ,RabbitMQ,Kafka等,甚至Java中的List也可以称为一个简单的消息队列,种类如此繁多,我们该如何选择呢?现在主流的消息队列可以分为两类,一类以kafka为代表,一类以RabbitMQ为代表,二者有很多相似的地方,也都有各自的优势。 那我们平时构建系统的时候,该选择哪种消息队列呢?这里我们将RbbitMQ与kafka做一下对比(因为他们都是spring默认集成的消息队列),以便于我们做出最优的选择。 RabbitMQ:关于rabbit的详细介绍这里不说,感兴趣的可以看我之前的文章,一句话rabbit作为传统意义上的消息队列,基于AMQP协议开发,倾向于做按各种规则的消息转发。 Kafka:关于kafka的详细介绍会在以后的文章里写,因为刚开始用,想深入了解后再写出来。 kafka更倾向于一个流式管道的概念,消息从一处流向另一处,吞吐量比rabbit更高。 接下来通过俩张图来理解他俩的设计与区别。 首先来看rabbit,他通过broker来进行统一调配消息去向,生产者通过指定的规则将消息发送到broker,broker再按照规则发送给消费者进行消费,消费者方可以选择消费方式为pull或者是broker主动push,支持的消费模式也有多种,点对点,广播,正则匹配等。 Kafka主要为高吞吐量的订阅发布系统而设计,主要追求速度与持久化。 kafka中的消息由键、值、时间戳组成,kafka不记录每个消息被谁使用,只通过偏移量记录哪些消息是未读的,kafka中可以指定消费组来实现订阅发布的功能。 了解了二者大体的区别以后,我们再来看具体的适用场景。 Kafka: 1.从A系统到B系统的消息没有复杂的传递规则,并且具有较高的吞吐量要求。 2.需要访问消息的历史记录的场景,因为kafak是持久化消息的,所以可以通过偏移量访问到那些已经被消费的消息(前提是磁盘空间足够,kafka没有将日志文件删除) 3.流处理的场景。 处理源源不断的流式消息,比较典型的是日志的例子,将系统中源源不断生成的日志发送到kafka中。 rabbit: 1.需要对消息进行更加细粒度的控制,包括一些可靠性方面的特性,比如死信队列。 2.需要多种消费模式(点对点,广播,订阅发布等) 3.消息需要通过复杂的路由到消费者。 最后是关于性能方面,众所周知,kafka的吞吐量优于rabbit,大约是100k/sec,而rabbit大约是20k/sec,但是这个不应该成为我们选择的主要原因,因为性能方面的瓶颈都是可以通过集群方案来解决的。 最后要说的是,没有最好的队列,只有最合适的队列。 参考:Understanding When to use RabbitMQ or Apache Kafka
「面试题」消息队列最全解析,说人话的面试解析
其实面试官主要是想看看:
为什么使用消息队列
其实就是问问你消息队列都有哪些使用场景,然后你项目里具体是什么场景,说说你在这个场景里用消息队列是什么?
面试官问你这个问题, 期望的一个回答 是说,你们公司有个什么 业务场景 ,这个业务场景有个什么技术挑战,如果不用 MQ 可能会很麻烦,但是你现在用了 MQ 之后带给了你很多的好处。
先说一下消息队列常见的使用场景吧,其实场景有很多,但是比较核心的有 3 个: 解耦 、 异步 、 削峰 。
看这么个场景。A 系统发送数据到 BCD 三个系统,通过接口调用发送。如果 E 系统也要这个数据呢?那如果 C 系统现在不需要了呢?A 系统负责人几乎崩溃......
在这个场景中,A 系统跟其它各种乱七八糟的系统严重耦合,A 系统产生一条比较关键的数据,很多系统都需要 A 系统将这个数据发送过来。A 系统要时时刻刻考虑 BCDE 四个系统如果挂了该咋办?要不要重发,要不要把消息存起来?头发都白了啊!
如果使用 MQ,A 系统产生一条数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。如果新系统需要数据,直接从 MQ 里消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消费即可。这样下来,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 系统就会快速将积压的消息给解决掉。
优点上面已经说了,就是 在特殊场景下有其对应的好处 , 解耦 、 异步 、 削峰 。
缺点有以下几个:
所以消息队列实际是一种非常复杂的架构,你引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉,做好之后,你会发现,妈呀,系统复杂度提升了一个数量级,也许是复杂了 10 倍。但是关键时刻,用,还是得用的。
综上,各种对比之后,有如下建议:
一般的业务系统要引入 MQ,最早大家都用 ActiveMQ,但是现在确实大家用的不多了,没经过大规模吞吐量场景的验证,社区也不是很活跃,所以大家还是算了吧,我个人不推荐用这个了;
后来大家开始用 RabbitMQ,但是确实 erlang 语言阻止了大量的 Java 工程师去深入研究和掌控它,对公司而言,几乎处于不可控的状态,但是确实人家是开源的,比较稳定的支持,活跃度也高;
不过现在确实越来越多的公司会去用 RocketMQ,确实很不错,毕竟是阿里出品,但社区可能有突然黄掉的风险(目前 RocketMQ 已捐给 Apache,但 GitHub 上的活跃度其实不算高)对自己公司技术实力有绝对自信的,推荐用 RocketMQ,否则回去老老实实用 RabbitMQ 吧,人家有活跃的开源社区,绝对不会黄。
所以 中小型公司 ,技术实力较为一般,技术挑战不是特别高,用 RabbitMQ 是不错的选择; 大型公司 ,基础架构研发实力较强,用 RocketMQ 是很好的选择。
如果是 大数据领域 的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。