消息队列

基础牢不牢先不管,我就要开搞消息队列(Message Queue)着一块,因为比较感兴趣,请大家不要模仿,基础还是很重要的~~

一、什么是消息队列

消息队列(message queue),顾名思义就是消息的队列。“消息”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象等。队列呢,稍微了解一点数据结构的人就会知道,它是一种线性结构,先进先出,后进后出(FIFO—first in first out)
,就跟我们排队买票一样。那么消息队列呢,它是在消息的传输过程中保存消息的容器。消息被发送到队列中,消息队列充当中间人,将消息从它的源中继到它的目标。所以消息队列也是一种中间件。

二、为什么使用消息队列

我们套用一个比较经典的例子来说明为什么使用消息队列吧。
【案例一】电商系统的支付模块正常流程,下单-> 支付,就完成了,很简单,没什么毛病(流程如图一);但是随着系的优化,我们在下单完成之后要进行发短信告知下单成功,增加用户积分等各种各样的操作,流程就会越来越复杂(如图二)
消息队列
我们可以很明显的看到,随着功能的完善,流程上增加了越来越多的节点。假设流程后面的数字为执行该模块时所消耗的时间,那么耗时也会越来越多,影响用户体验。
我们再仔细想一下,我们在提交订单的时候,对‘发短信’和‘增加积分’等功能是特别关注的吗?并不是,这些操作明明可以在下单完成之后再完成的。这一部分时间不应该让用户来进行等待。换言之,这些操作应该异步执行。
消息队列
说起异步,大家第一时间可能会想到多线程,没错,这也是一种解决方案。简单一点的项目也确实可以这么做。但它的弊端也是很明显的,如果再增加一些其他的功能模块,比如给商家发通知等,我们是不是就需要再写一个线程来进行修改,然后每次加一个你要调用一个接口然后还要重新发布系统,成本太高而且多线程也会增加内存的消耗。而且真的全部都写在一起的话,不单单是耦合这一个问题,你出问题排查也麻烦,流程里面随便一个地方出问题搞不好会影响到其他的点~~
既然不建议使用多线程的话那怎么办,今天的主题-消息队列就是一种很好的解决方式
消息队列
当你下单后,你就把你支付成功的消息告诉别的系统,他们收到了去处理就好了,你只用走完自己的流程,把自己的消息发出去,剩下的交给兄弟们解决就可以了。这样做我们可以称之为解耦
上边也只是正常的逻辑,但是在实际操作中肯定会出现很多比如没有增加积分啊,没有发短信之类的问题,也就是消息消费失败了。这样的问题导致的结果也是比较严重的,我们后边再进行详细介绍。
【案例二】某小型电商网站服务器只有一台机器,每台机器只能每次处理1000个请求。正常运营过程中是完全没有问题的。但是在618大促,双十一淘宝活动的时候,尤其是各种秒杀的活动,每秒过来5000次请求,怎么办,系统直接崩溃了哈哈~~
此时呢,消息队列的优势就展现出来了,5000个请求过来了是吧,排队别挤,一个一个来,1000个1000个分拨走,分开执行。这样系统就可以把压力分摊开一些。猪肘子好吃也不能一口全吃完吧,一口一口慢慢的吃,细嚼慢咽,既有营养而且还美味~。这种操作我们称之为削峰
如果你注意查看了,你会发现上边我们特别标注了3个关键词【异步】,【解耦】,【削峰】,没错这三个关键词就是消息队列的核心了,提及消息队列,一定一定要想到异步解耦削峰,记得死死的那种。

三、使用消息队列带来的一些问题

  • 系统可用性降低: 系统可用性在某种程度上降低,为什么这样说呢?在加入MQ之前,你不用考虑消息丢失或者说MQ挂掉等等的情况,但是,引入MQ之后你就需要去考虑了!
  • 系统复杂性提高: 加入MQ之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题! 一致性问题:
  • 一致性问题:消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了!

四、常用的消息队列中间件

目前在市面上比较主流的消息队列中间件主要有,Kafka、ActiveMQ、RabbitMQ、RocketMQ 等这几种。对比一下

特性 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 功能,在大数据领域的实时计算以及日志采集被大规模使用

ActiveMQ和RabbitMQ这两者因为吞吐量还有GitHub的社区活跃度的原因,在各大互联网公司都已经基本上绝迹了,业务体量一般的公司会是有在用的,但是越来越多的公司更青睐RocketMQ这样的消息中间件了。

RocketMQ天生为金融互联网领域而生,对于可靠性要求很高的场景,尤其是电商里面的订单扣款,以及业务削峰,在大量交易涌入时,后端可能无法及时处理的情况。RoketMQ在稳定性上可能更值得信赖,这些业务场景在阿里双11已经经历了多次考验,如果你的业务有上述并发场景,建议可以选择RocketMQ。

Kafka主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输,适合产生大量数据的互联网服务的数据收集业务。大型公司建议可以选用,如果有日志采集功能,肯定是首选kafka了。