作者 | ithuangqing
来源 | 编码之外(ID:ithuangqing)
今天,我们一起来看看,消息队列是个啥?
消息队列是否了解?
消息队列初步来看,是由“消息”和“队列”组成,英文叫做:Message Queue,一般这些玩意都会根据英文名称来个简称,而简称一般就是英文名字的首字母缩写,所以消息队列即MQ。
可能你对消息队列有点陌生,但是你一定听过消息队列四个字,而且还会听过或者在其他地方见过比如RabbitMQ,还有RocketMQ,如果这些你都没听过,那你一定听过Kafka吧,这些知识可能在你那里都是高大上的概念,自己觉得目前还学不来这些知识……
所以,我觉得应该有相当一部分只是听过这些名字,但是仅仅而已,再多一点的信息可能就不知道了,那么从现在开始,跟随庆哥,一起来学习消息队列吧,同样的,庆哥会用大白话给你讲解这些晦涩难懂的概念与技术。
中间件是否了解
其实消息队列属于一种中间件,这个中间件,我想大部分应该也听过,但是也不太清楚是个什么玩意,其实吧,在编程世界里啊,很多解决不了的问题,都可以加个中间件来搞定,中间件,名字已经很直白了,就是相当于一个桥梁,比如A与B有直接关系,但是现在A和B之间引入了一个c,那么c就可以看做一个中间件,A和B依然可以通信,只不过不是直接通信,要借助c来实现了,画个图,简单的就是这样:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5f95e4b0255b587eba5a6be0f8e72917.png)
而消息队列就是属于一种中间件,充当了一个桥梁作用, 相当于在原有的基础之上强塞了一个玩意过去,以后原有的需要做些什么,可能就要经过这个新来的中间件了。
消息队列到底是个啥?
那消息队列有啥用嘞?以上,我们知道了消息队列是个中间件,哪还有啥嘞?就知道个中间件也不起作用啊,还是对消息队列一脸懵逼吧,想要搞定消息队列是个啥?我们得从字面意思上去拆解,首先,什么是消息你知道吗?
消息这个不多说, 属于不言而喻的东西,那么啥是队列,这个可能就有人不清楚了,不过不用担心,我之前特意写过一篇讲解队列的文章,你可以去看看:轻轻松松学会栈和队列(附有顺序栈的实现思路分析)
加入你已经看了这篇文章了,也许现在你已经知道了啥是队列,我相信,你知道的依旧是个概念,也就是队列的那些特点啥的,比如是个数据结构啊,什么先进先出啊,有什么队头和队尾之嘞的。
这些都是概念性的问题,如果你是第一次接触队列的话,我相信,你内心还是迷茫的,这都是啥啊,你可能会问。
其实吧,队列是属于一种数据结构,数据结构这玩意刚开始学习很玄学,不知道所以然,数据结构其实就是在告诉你,数据该怎么进行存储,按照一些特定的规则以及方式去储存数据,简单来说这就是数据结构在做的事情。
就拿数组来说,如果你需要用数组的话,那么实际上就是取内存申请了一段连续的内存空间,这个连续就是一个特点,要求你这些数据必须连续存储在这些内存中……
队列其实也是一样,说到底,就是告诉你怎么在内存中存储数据,记住这个先,那消息队列,也是这样,很直白的按照字面意思理解,就是存储消息的队列,所以啊,消息队列就是用来存储信息,然后其他可以从它这获取信息。
总结的说,消息队列是进行消息的收发,可以起到一个通信的作用,毕竟消息是可以传递信息的,你打个电话,发个短信,这都是在传递信息啊,这不都是通信嘛,这个应该不难理解!
所以记住,消息队列:消息收发,通信
这么一看,消息队列好像就起到了一个通信的作用?当然不是,通信只是一部分,它所起到的作用绝对不仅仅如此。
我上面说了这么多,其实就是在跟你掰扯,消息队列是啥?不知道你清楚了没有,如果别人问你,知道消息队列吗?你必须回答,知道啊,消息队列,是一种中间件,进行消息的收发,可以解决一些通信问题……
当然,你这样回答远远不够,你还必须知道以下这些关于消息队列的知识。
有哪些消息队列
首先你得知道,消息队列MQ是一个统称,具体的有不同的产品,啥意思咧,就比如说水果,那还包括香蕉和苹果嘞,所以,消息队列有好几种嘞,我这里说几种当下比较流行的,其实也就三种:
RabbitMQ
RocketMQ
Kafka
这三种,上面也简单提过,可能你们也听说过,只是没有具体的去学习过,那么从现在开始,也就是看了我这次的分享这后,别人再问起消息队列,最起码你能够把这三个给说出来,并且还能对他们挨个做下介绍。
RabbitMQ
这个消息队列比较老牌了,这个俗称兔子MQ,至于为啥这样说,你应该知道。
RabbitMQ在一开始是很强势的,也就是曾经很辉煌,当然,现在也不赖,只不过由于一些后起之秀,光芒不胜从前了,毕竟后来的也很优秀,RabbitMQ它的特点你需要记住:
开箱即用
轻量级
易于部署和使用
支持灵活的路由配置
客户端支持的编程语言是最多的(至少目前是)
……
知道以上几个就差不多了,当然,你还得知道RabbitMQ的几个不好地方:
使用Erlang语言编写(这是个啥语言我之前真不知道,这就导致一个大问题,想要二次开发与扩展,以及遇到问题的话,解决的成本都比较高啊)
对消息堆积支持的不友好(消息队列就是进行消息收发的啊,大量的消息扔进RabbitMQ的话,它的性能表现就不那么好了)
性能相比较RocketMQ和Kafka是最差的
关于RabbitMQ,你目前就需要知道这些就行了,因为每一种消息队列产品都是值得我们单独花时间学习和研究的,所以这里我们肯定介绍不了那么多,这个以后会单独学习他们,到那时候再分享。
RocketMQ
这个就比较牛了,好像现在差不多都在用这个吧,不过还是分场景吧,不同的应用场景应该选择不同的消息队列,RocketMQ属于明星产品啊,它是阿里巴巴搞出来的,后来捐赠给了Apache基金会,2017年成了其顶级项目,阿里内部也是使用的它。
可以说,RocketMQ是一款综合变现都很不错的消息队列产品,无论是性能还是稳定性,亦或是可靠性,RocketMQ表现的都很不错,反正吧,这家伙是越来越首欢迎了。
那么咱们来看看它的一些特点吧:
用java语言开发,好处多多啊
响应时延这块优化的很好(就是响应时间优化的很短)
性能优越,比兔子MQ好
那要说它有什么不好的地方,那可能就是因为它是我们国人开发的,在于世界上其他优秀的产品协作的时候,集成和兼容性问题上可能有点不足,不过啊,这算得上是问题吗?????
Kafka
这个家伙,我之前可是经常听到它,它相比较前两者,虽然都是消息队列中间件,但是它似乎有点另类,就从名字上看,人家都是啥啥啥MQ,这家伙直接叫做Kafka(卡夫卡),还是很有个性的。
它一开始是为了用于处理海量日志的,所以啊,它与大数据关系颇深,它在处理海量日志啊,或者是监控信息,以及流计算这些的时候,无疑是最好的选择。
而且Kafka可以说是与周边开源产品兼容最好的一个中间件,也就是说,几乎所有的相关开源软件系统都会优先支持Kafka。
另外它使用java和Scala编写,在性能,稳定性和可靠性上也都表现优异,这么一看,这家伙好像是集万众宠爱于一身啊,妥妥的老大啊,各方面都很优异啊。
但是它对消息是进行异步批量进行处理的,这就带来一个问题,延迟比较高,这点他是比不上RocketMQ。
因此嘞,这家伙不太适合在线业务场景。
该怎么选择这些消息队列嘞?
经过对上面的集中流行的消息队列中间件的介绍,你大致可以跟别人简单介绍下他们,那么接下来的问题就是该怎么选择他们的问题。
其实也很简单,根据不同的应用场景和需求去选择他们。
什么场景下该选择RabbitMQ,什么场景下该选择RocketMQ,什么场景下又该选择Kafka呢?
首先对于RabbitMQ,我们讲到它的时候,可能最先想到的就是它的轻量,开箱即用易于维护,所以基于这个特点,如果你的项目需要用到消息队列,但是消息队列又不是你系统的主角,那么RabbitMQ是一个不错的选择。
当然,如果对于你的系统,消息队列扮演着重要的角色,对性能,稳定性以及可靠性等都有一定的要求,更重要的是你需要使用消息队列来处理在线业务场景,那么你最好选择RocketMQ,因为它优越的低延迟,以及优秀的稳定性绝对会给你给力的表现。
如果你是需要处理海量的信息,业务涉及大数据,流计算等,那么这样的情况下,Kafka无疑是最好的选择了。
消息队列的常见应用场景?
到了这里你就该去思考下,碰到什么样的问题,你需要使用消息队列呢?这也是常见的面试题,消息队列有哪些常见应用场景,这个是你必须要知道的。
提到这个,熟悉消息队列的可能立马就会说出三个词:异步,削峰和解耦,啥意思嘞?如果之前不了解消息队列的话,听到这三个,一定会觉得有那么点东西啊,我竟然都不知道,对于属于的而言,一听就知道接下来你要讲的是啥。
所以嘞,接下来我主要给那些之前还不知道的说道说道。
异步
这里主要指的是服务的异步请求,啥意思嘞,一般提到这个,很多人都会提到秒杀系统,因为秒杀系统一定会使用到消息队列,也比较好用来解释消息队列的一些特性。
不过提到秒杀系统,估计有些人也是一脸懵逼,这也是经常听说,但是觉得很高大上,自己又没有学习的玩意啊,其实一个秒杀系统,我也没有设计过,具体涉及的技术栈,我也不是很清楚,但是我知道这一点就够了,最起码够我去理解消息队列的异步使用场景了,那是啥嘞?
所谓的秒杀系统,其中必定有的就是在同一时间内,会有大量的服务请求过来。
知道这个,咱们就可以来看看这个服务异步了,秒杀系统中要处理的一个问题就是短时间内,有大量的请求过来,这个你得处理啊,不然服务器一时间承受不了这么大的请求数量,那服务器会被搞死的,那怎么办嘞?
解决办法也很简单,那就是加入消息队列,那为啥要加入消息队列啊,我们得来再看看这个秒杀系统,秒杀系统这个一般就是定一个时间点,或者时间段,某个火爆的商品开始挥泪大甩卖,我们人呐都是喜欢贪便宜的,所以这个必须得抢啊,于是都提前订好闹钟,一到时间,里面点击立即购买,然后下单,然后成功抢到,然后付款,然后发货……有的还会即时发消息给你,“恭喜你这个崽,成功抢到这次的商品……”
我们来简单分析下这个流程,首先,你点击立即购买,然后简单点,就是你抢到了,让你付款,接着提示你付款成功,然后给你发货,发消息,但是你想过没有,这个时候可不是你一个人做这些操作啊,可能有成千上万个,这个时候这个商品服务系统就没有那么快了,可能你点了立即购买,迟迟不见付款界面,为啥,因为这个时候再处理其他用户的请求。
这个当中你还得明白一点,就是在这个秒杀操作中,比如这个商品库存就有1000个,但是现在有一万人来抢,那么当你点击立即购买的时候,如果你网速够快,你够幸运抢到了,那么其实在后台,就会进行库存锁定,也就是剩余库存会减去你抢到的这些,然后会给你生成订单,让你付款,你可以想一下,当有很多人来做这个操作的时候,因为其中会处理别人的请求,所以你的请求就不会立马得到响应,可能这其中还有什么可以用积分抵扣,那么还要去做积分的相应扣减,可能还有什么优惠券之类的,会员特权之类的啊,都会做相应的操作
说这么多就是想说,你可能要等很久,页面也没有响应,你也不知道自己有没有秒杀成功,所以啊这样的话,用户体验就很差,你可能就要骂了“这什么垃圾APP啊”。
怎么解决嘞?你其实可以想想,这其中是不是只要你的请求过来成功进行库存锁定,也就是确定有你这一份了,那么剩下的相关操作,比如扣积分之类的,生成订单啥的,其实可以先不用管,只要库存一旦锁定成功,就可以立马给你返回“秒杀成功”,这样岂不美滋滋。
那怎么实现嘞,其实就是使用消息队列,一旦你秒杀成功,成功进行库存锁定,这个时候就可以把请求的相关数据放进消息队列中,然后给你返回结果,至于后续的积分,订单甚至给你发短信,则有相应的系统去从消息队列去拿到这个请求的数据,然后去处理,而这个其实并不要求你立马完成。
这么一来,我们就可以把大量的服务资源去处理这个秒杀请求,至于其他的后续操作则可以交由消息队列去由其他系统进行异步操作
这有啥好处嘞,显而易见的就是我们可以更快的接收到处理结果,而且整体系统的性能也提高了。
削峰
这个完整的叫做“削峰填谷”,听起来很是高大上啊,其实我觉叫做流量控制更加好理解,啥意思嘞,还是拿这个秒杀系统来说,当短时间内大量秒杀请求过来的时候,服务器一时间处理不了这么多请求,有可能把服务器给搞死。
这个时候我们可以加入消息队列,管你来多少请求嘞,统统把这些请求给你放到消息队列中,然后看我们服务器的处理能力,能够处理多少,就从消息队列中拿出,对于那些暂时没法处理的请求,也很有可能就会发生请求超时,一般这种情况也就意味着你秒杀失败了,那直接给用户返回“秒杀失败”的通知就可以了。
这样就可以很好的避免,因为大量请求而把我们的系统服务搞死的情况了。
但是这样也会产生一些新的问题,比如之前有请求回来,都是我们的服务器去直接处理,而现在嘞,中间多了一个消息队列,消息需要进去,我们的服务器需要从消息队列中去拿,这样一来,就增加了调用的复杂度,那么相应的响应时间也就变长了,整体系统也变得比之前复杂了,这个也是你需要知道的。
这就是我们说的削峰了,其实还是叫流量控制比较好理解吧。
解耦
最后一个就是关于解耦了,这个我们有些朋友可能知道,啥是解耦,一般就是一些系统啥的,之间互相依赖,你需要我,我有需要它,你我他之间是高度依赖的,如果其中出现一个问题的话,那其他的也受到影响,那么这个时候就需要解耦,解耦的目的就是把你我他隔离开来,大家互不影响。
举个例子吧,比如我们下单这个操作,当你下单完成之后,可能还会有一些其他的操作,因为这些操作都是需要得到你下单的数据之后才能进行相应的操作,这个时候他们之间就是高度依赖的,如果这些下单之后的相应系统有一些改变,那么下单这个操作可能就需要做一些改变。
总的来说,下单之后的一些操作高度依赖下单这个动作,反过来,下单后的这些操作也间接影响着下单这个动作,这样他们之间高度依赖,如果有什么问题,可能都需要进行改动,也就是所谓的,牵一发而动全身,好像是这么说来着。
这肯定不行啊,怎么解决嘞?那就是引入消息队列来解决,也就是下单成功了,把下单的数据放进消息队列,需要用到这个下单数据的其他系统,自动订阅这个消息队列,从消息队列中去取数据,这么一来下单和下单之后的一些操作就隔开了,下单只管下单的,下单成功,就不管你后续的操作啥的,后面的其他系统如果需要这个下单数据,那就去消息队列中去拿,下单这个本身才不管你们这些嘞。
其实吧,我觉得这个解耦和异步有点相像,不知道你们怎么看?
使用消息队列有什么问题吗?
我们上面唠唠叨叨的把消息队列给说了说,觉得消息队列很好用啊,那么使用消息队列有没有什么问题呢?
这个其实是很定的,作为一种中间件,使用了消息队列,那就意味着增加了系统的复杂性,除此之外,基于消息队列的特点,它可能发生这么些问题:
消息队列这个中间件如果挂了怎么整?
消息放进了消息队列中,真的一定能放进去,会不会把我放进去的消息整丢了
会不会有重复的消息放进消息队列?
如果消息队列中的消息越放越多,而又不被消费,那么消息堆积了咋整
……
等等吧,这些都是消息队列会遇到的问题,可能有些人会问了,那么这个怎么解决啊,一般的主流的消息队列产品肯定都考虑到了这些问题,而且也都做了相应的处理,你就比如RocketMQ来说,一般你做好相应的配置啥的,就不会出现消息丢失的情况。
也就是说,不同的消息队列产品都有自己的应对办法,具体是怎样的,那就得看齐消息队列本身了,这个以后我们再说,今天关于消息队列的介绍就先到这里。
有什么问题,欢迎大家留言讨论!
-END-
如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「web_resource」,欢迎添加小编微信「focusoncode」,每日朋友圈更新一篇高质量技术博文(无广告)。
↓扫描二维码添加小编↓
推荐阅读
1. 那些神一样的程序员
2. 16000 字 Redis 面试知识点总结,建议收藏!
4. 高频使用的 Git 命令