背景
程序员不懂点消息队列的知识,怎么能证明你经历过高并发系统的洗礼呢?看起来你的项目经历比较单一和简单嘛,面试官在心里应该有点看低你这位候选人了。就算你的项目里没有用到,为了面试,你也得懂得一些消息队列的基本原理及常见面试套路吧!
为什么使用消息队列
你们的项目中有用到消息队列吗?为什么要使用消息队列呢?
都说学以致用,不少候选人为了丰富自己的简历,会说自己精通XXX语言,项目中使用了Redis、MQ,知道已经使用,但如果为为何使用,就回答不出什么道道来。
这种情况下,面试官会以为,你只是一个普通干活的,平时可能只是CURD操作,修补bug,只是了解项目一些细枝末节,对于项目的整体设计架构,没有自己的独立思考,这样人想达到中级工程师的水平也有点难啊,面试官会在心里对你的整体印象大大打折。
消息队列的为什么使用必须结合项目的场景来说。项目场景有高并发,低延迟的需求,可能需要引入消息队列,但引入消息队列同时也会带来一些问题,这是下一个需要考虑的问题。
消息队列引入的主要原因有三个:解耦、异步和削峰。
-
解耦
一般公司的项目,在构建初期,一个服务里面就揉进去很多功能,敏捷开发嘛,快速迭代上线。举个例子,S1系统产生的用户数据源,可能会被S2、S3系统调用,后来又新增了S4系统,每次有系统的增删,负责S1系统的开发人员都需要修改代码,测试,上线,简直烦不胜烦。
如果改为S1系统将数据打入消息队列,哪个系统想要使用数据,直接消费消息队列就ok了,世界真清净。谁来接入我谁来负责,我只用管打入消息队列是ok的就行。S1系统的开发人员可以悠闲喝茶知道别人怎么接入了!
-
异步
一般的服务,肯定会与存储打交道,涉及到存储一般有MySQL、MongoDB、Hbase或其他存储。如下图,假设,S1系统只是一些本地内存操作,耗时5ms,S2、S3写库为MySQL和Hbase,耗时分别是50ms和80ms,那系统的总耗时就是5+50+80=135ms。
虽然当前用户访问延时为135ms,速度也还可以了,但如果又增加了S4、S5系统呢,访问延迟是逐渐增加的啊,到时候就会有人抱怨你的系统做的太烂了。如果改为消息队列呢,S1将数据打入MQ,耗时5ms,总的系统延迟就是5+5=10ms,而且解耦了,再增加其他服务访问延迟还是10ms,网站做的666啊,速度飞快。
-
削峰
任何公司的任何业务,都会有流量的高峰和低谷,每天00:00-6:00,系统访问低谷,请求并发量可能就几十个,一切很美好。但到了12:30-13:00,访问流量竟然能达到10000/s,也是佩服公司的运营人员和公司的产品啊,产品访问量大好啊,说明业务蒸蒸日上,但开发哥哥就没这么好过了,并发量大,对数据持久层的访问时个考验。
假设当前S1系统访问的MySQL还没有做分库分表的优化,那能抗住的QPS的上线就是2000左右。
高峰达到了10000/s啊,去做分库分表,申请资源又有些浪费,因为在流量低谷时,只有几十的qps,这时候使用消息队列就比较合适了。这里只是举简单的例子,实际的系统处理起来肯定没这么简单了。延迟太多用户可要被抢走了!
消息队列有什么优缺点
假如你说了这些,面试官心里应该默默赞许,小伙子不错嘛,优点基本都答出来了,那再问问你缺点。
万事都有两面性,有好就有坏。缺点大致有以下几个:
-
可用性降低
服务中引入的依赖越多,引入的外部组件越多,维护的成本就越高,本来你只是S1调用S2、S3服务即可。引入了消息队列,消息队列打入失败怎么办?消息队列挂了怎么办?怎么保证消息队列的稳定性?这些就需要后面再说了!
-
复杂度变高
消息重复消费怎么办?消息丢失怎么办?如果要求消费的消息有序又怎么搞?本来在一个S1里,这些问题都好解决,加了一个MQ,这下麻烦大了!
-
一致性
用户请求S1返回成功,是真的成功了吗?当然不是,这只是代表打入MQ成功了啊。但这是如果消费MQ的某个服务挂了怎么办?你怎么监控,怎么处理数据一致性问题,真是搞的头都大了。
引入消息队列,有很多优点,但同时也带来了很多缺点,但是为了提高系统的响应速度,高并发情况下还是要用的。
消息队列的选型
缺点说的也头头是道嘛,面试官已经悄悄的在背后竖起了大拇指,小伙子不错,有一定的架构思维,之道引入一个组件的优缺点。并不是只知其一不知其二,只知道干活的人!
那你们关于消息队列是怎么选型的呢?
这就要从各个消息队列的一些特性说起了。
特性 | 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 功能,在大数据领域的实时计算以及日志采集被大规模使用 |
对比之后:
一般来说,现在选择RocketMQ,阿里出品,也已经捐献给Apache,社区还算活跃。单机吞吐量及可用性也都可以满足需求,后续分布式扩展功能支持也较好。
如果数据量非常大,偏向于大数据领域的实时计算及日志采集处理,且要求高可用,Kafka绝对是不二选择!
重复消费你们是怎么解决的?
面试官又丢给你一个问题,重复消费,其实也就是消息幂等处理的问题?
首先什么情况会造成重复消费呢?
Kafka的consumer消费有个offset的概念,consumer消费数据之后,定期提交offset,如果提交过程中,系统无故宕机或重启或网络原因,提交失败,那consumer就还会从上一个offset开始消费数据,这就是重复消费。
重复消费是消息队列中非常常见的问题,只要保证幂等处理就可以,比如你可以用Redis或MySQL记录下以处理消息的唯一id,碰到重复处理的消息,直接忽略即可!
小伙子,你知道的太多了,我都想让你明天直接来上班了,但是不行,还是得让下一位面试官来做做面试的样子!😝!敬请期待下一期小灶!
程序员的小伙伴们,觉得自己孤单么,那就加入公众号[程序员之道],一起交流沟通,走出我们的程序员之道!