Kafka、ActiveMQ、RabbitMQ、RocketMQ区别以及⾼可⽤原理
为什么使⽤消息队列
其实就是问问你消息队列都有哪些使⽤场景,然后你项⽬⾥具体是什么场景,说说你在这个场景⾥⽤消息队列是什么?⾯试官问你这个问题,期望的⼀个回答是说,你们公司有个什么业务场景,这个业务场景有个什么技术挑战,如果不⽤MQ 可能会很⿇烦,但是你现在⽤了 MQ 之后带给了你很多的好处。
先说⼀下消息队列常见的使⽤场景吧,其实场景有很多,但是⽐较核⼼的有 3 个:解耦、异步、削峰。
解耦
看这么个场景。A 系统发送数据到 BCD 三个系统,通过接⼝调⽤发送。如果 E 系统也要这个数据呢?那如果 C 系统现在不需要了呢?A 系统负责⼈⼏乎崩溃......
在这个场景中,A 系统跟其它各种乱七⼋糟的系统严重耦合,A 系统产⽣⼀条⽐较关键的数据,很多系统都需要 A 系统将这个数据发送过来。A 系统要时时刻刻考虑 BCDE 四个系统如果挂了该咋办?要不要重发,要不要把消息存起来?头发都⽩了啊!
如果使⽤ MQ,A 系统产⽣⼀条数据,发送到 MQ ⾥⾯去,哪个系统需要数据⾃⼰去 MQ ⾥⾯消费。如果
新系统需要数据,直接从 MQ ⾥消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消费即可。这样下来,A 系统压根⼉不需要去考虑要给谁发送数据,不需要维护这个代码,也不需要考虑⼈家是否调⽤成功、失败超时等情况。
总结:通过⼀个 MQ,Pub/Sub 发布订阅消息这么⼀个模型,A 系统就跟其它系统彻底解耦了。
⾯试技巧:你需要去考虑⼀下你负责的系统中是否有类似的场景,就是⼀个系统或者⼀个模块,调⽤了多个系统或者模块,互相之间的调⽤很复杂,维护起来很⿇烦。但是其实这个调⽤是不需要直接同步调⽤接⼝的,如果⽤ MQ 给它异步化解耦,也是可以的,你就需要去考虑在你的项⽬⾥,是不是可以运⽤这个 MQ 去进⾏系统的解耦。在简历中体现出来这块东西,⽤ MQ 作解耦。
异步
activemq启动报错再来看⼀个场景,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 系统就会快速将积压的消息给解决掉。
消息队列有什么优缺点
优点上⾯已经说了,就是在特殊场景下有其对应的好处,解耦、异步、削峰。
缺点有以下⼏个:
•系统可⽤性降低
•系统引⼊的外部依赖越多,越容易挂掉。本来你就是 A 系统调⽤ BCD 三个系统的接⼝就好了,⼈ ABCD 四个系统好好的,没啥问题,你偏加个 MQ 进来,万⼀ MQ 挂了咋整,MQ ⼀挂,整套系统崩溃的,你不就完了?如何保证消息队列的⾼可⽤
•系统复杂度提⾼
•硬⽣⽣加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?头⼤头⼤,问题⼀⼤堆,痛苦不已。
•⼀致性问题
•A 系统处理完了直接返回成功了,⼈都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那⾥,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不⼀致了。
所以消息队列实际是⼀种⾮常复杂的架构,你引⼊它有很多好处,但是也得针对它带来的坏处做各种额外的技术⽅案和架构来规避掉,做好之后,你会发现,妈呀,系统复杂度提升了⼀个数量级,也许是复杂了 10 倍。但是关键时刻,⽤,还是得⽤的。
Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么优缺点?
特性ActiveMQRabbitMQRocketMQKafka单机吞吐量万级,⽐ RocketMQ、Kafka 低⼀个数量级同 ActiveMQ10 万级,⽀撑⾼吞吐10 万级,⾼吞吐,⼀般配合⼤数据类的系统来进⾏实时数据计算、⽇志采集等场景topic 数量对吞吐量的影响 topic 可以达到⼏百/⼏千的级别,吞吐量会有较⼩幅度的下降,这是 RocketMQ 的⼀⼤优势,在同等机器下,可以⽀撑⼤量的 topictopic 从⼏⼗到⼏百个时候,吞吐量会⼤幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要⽀撑⼤规模的 topic,需要增加更多的机器资源时效性ms 级微秒级,这是 RabbitMQ 的⼀⼤特点,延迟最低ms 级延迟在 ms 级以内可⽤性⾼,基于主从架构实现⾼可⽤同 ActiveMQ⾮常⾼,分布式架构⾮常⾼,分布式,⼀个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可⽤消息可靠性有较低的概率丢失数据基本不丢经过参数优化配置,可以做到 0 丢失同 RocketMQ功能⽀持MQ 领域的功能极其完备基于 erlang 开发,并发能⼒很强,性能极好,延时很低MQ 功能较为完善,还是分布式的,扩展性好功能较为简单,主要⽀持简单的 MQ 功能,在⼤数据领域的实时计算以及⽇志采集被⼤规模使⽤
综上,各种对⽐之后,有如下建议:
⼀般的业务系统要引⼊ MQ,最早⼤家都⽤ ActiveMQ,但是现在确实⼤家⽤的不多了,没经过⼤规模吞吐量场景的验证,社区也不是很活跃,所以⼤家还是算了吧,我个⼈不推荐⽤这个了;
后来⼤家开始⽤ RabbitMQ,但是确实 erlang 语⾔阻⽌了⼤量的 Java ⼯程师去深⼊研究和掌控它,对公司⽽⾔,⼏乎处于不可控的状态,但是确实⼈家是开源的,⽐较稳定的⽀持,活跃度也⾼;
不过现在确实越来越多的公司,会去⽤ RocketMQ,确实很不错(阿⾥出品),但社区可能有突然黄掉的风险,对⾃⼰
不过现在确实越来越多的公司,会去⽤ RocketMQ,确实很不错(阿⾥出品),但社区可能有突然黄掉的风险,对⾃⼰公司技术实⼒有绝对⾃信的,推荐⽤ RocketMQ,否则回去⽼⽼实实⽤ RabbitMQ 吧,⼈家有活跃的开源社区,绝对不会黄。
所以中⼩型公司,技术实⼒较为⼀般,技术挑战不是特别⾼,⽤ RabbitMQ 是不错的选择;⼤型公司,基础架构研发实⼒较强,⽤ RocketMQ 是很好的选择。
如果是⼤数据领域的实时计算、⽇志采集等场景,⽤ Kafka 是业内标准的,绝对没问题,社区活跃度很⾼,绝对不会黄,何况⼏乎是全世界这个领域的事实性规范
如何保证消息队列的⾼可⽤?
RabbitMQ 的⾼可⽤性
RabbitMQ 是⽐较有代表性的,因为是基于主从(⾮分布式)做⾼可⽤性的,我们就以 RabbitMQ 为例⼦讲解第⼀种MQ 的⾼可⽤性怎么实现。
RabbitMQ 有三种模式:单机模式、普通集模式、镜像集模式。
单机模式
单机模式,就是 Demo 级别的,⼀般就是你本地启动了玩玩⼉的
,没⼈⽣产⽤单机模式。
普通集模式(⽆⾼可⽤性)
普通集模式,意思就是在多台机器上启动多个 RabbitMQ 实例,每个机器启动⼀个。你创建的 queue,只会放在⼀个RabbitMQ 实例上,但是每个实例都同步 queue 的元数据(元数据可以认为是 queue 的⼀些配置信息,通过元数据,可以到 queue 所在实例)。你消费的时候,实际上如果连接到了另外⼀个实例,那么那个实例会从 queue 所在实例上拉取数据过来。
这种⽅式确实很⿇烦,也不怎么好,没做到所谓的分布式,就是个普通集。因为这导致你要么消费者每次随机连接⼀个实例然后拉取数据,要么固定连接那个 queue 所在实例消费数据,前者有数据拉取的开销,后者导致单实例性能瓶颈。
⽽且如果那个放 queue 的实例宕机了,会导致接下来其他实例就⽆法从那个实例拉取,如果你开启了消息持久化,让RabbitMQ 落地存储消息的话,消息不⼀定会丢,得等这个实例恢复了,然后才可以继续从这个 queue 拉取数据。
所以这个事⼉就⽐较尴尬了,这就没有什么所谓的⾼可⽤性,这⽅案主要是提⾼吞吐量的,就是说让集中多个节点来服务某个 queue 的读写操作。
镜像集模式(⾼可⽤性)
这种模式,才是所谓的 RabbitMQ 的⾼可⽤模式。跟普通集模式不⼀样的是,在镜像集模式下,你创建的 queue,⽆论元数据还是 queue ⾥的消息都会存在于多个实例上,就是说,每个 RabbitMQ 节点都有这个 queue 的⼀个完整镜像,包含 queue 的全部数据的意思。然后每次你写消息到 queue 的时候,都会⾃动把消息同步到多个实例的 queue 上。
那么如何开启这个镜像集模式呢?其实很简单,RabbitMQ 有很好的管理控制台,就是在后台新增⼀个策略,这个策略是镜像集模式的策略,指定的时候是可以要求数据同步到所有节点的,也可以要求同步到指定数量的节点,再次创建 queue 的时候,应⽤这个策略,就会⾃动将数据同步到其他的节点上去了。
这样的话,好处在于,你任何⼀个机器宕机了,没事⼉,其它机器(节点)还包含了这个 queue 的完整数据,别的consumer 都可以到其它节点上去消费数据。坏处在于,第⼀,这个性能开销也太⼤了吧,消息需要同步到所有机器上,导致⽹络带宽压⼒和消耗很重!第⼆,这么玩⼉,不是分布式的,就没有扩展性可⾔了,如果某个 queue 负载很重,你加机器,新增的机器也包含了这个 queue 的所有数据,
并没有办法线性扩展你的 queue。你想,如果这个queue 的数据量很⼤,⼤到这个机器上的容量⽆法容纳了,此时该怎么办呢?
Kafka 的⾼可⽤性
Kafka ⼀个最基本的架构认识:由多个 broker 组成,每个 broker 是⼀个节点;你创建⼀个 topic,这个 topic 可以划分为多个 partition,每个 partition 可以存在于不同的 broker 上,每个 partition 就放⼀部分数据。
这就是天然的分布式消息队列,就是说⼀个 topic 的数据,是分散放在多个机器上的,每个机器就放⼀部分数据。
实际上 RabbmitMQ 之类的,并不是分布式消息队列,它就是传统的消息队列,只不过提供了⼀些集、HA(High Availability, ⾼可⽤性) 的机制⽽已,因为⽆论怎么玩⼉,RabbitMQ ⼀个 queue 的数据都是放在⼀个节点⾥的,镜像集下,也是每个节点都放这个 queue 的完整数据。
Kafka 0.8 以前,是没有 HA 机制的,就是任何⼀个 broker 宕机了,那个 broker 上的 partition 就废了,没法写也没法读,没有什么⾼可⽤性可⾔。
⽐如说,我们假设创建了⼀个 topic,指定其 partition 数量是 3 个,分别在三台机器上。但是,如果第
⼆台机器宕机了,会导致这个 topic 的 1/3 的数据就丢了,因此这个是做不到⾼可⽤的。
Kafka 0.8 以后,提供了 HA 机制,就是 replica(复制品)副本机制。每个 partition 的数据都会同步到其它机器上,形成⾃⼰的多个 replica 副本。所有 replica 会选举⼀个 leader 出来,那么⽣产和消费都跟这个 leader 打交道,然后其他replica 就是 follower。写的时候,leader 会负责把数据同步到所有 follower 上去,读的时候就直接读 leader 上的数据即可。只能读写 leader?很简单,要是你可以随意读写每个 follower,那么就要 care 数据⼀致性的问题,系统复杂度太⾼,很容易出问题。Kafka 会均匀地将⼀个 partition 的所有 replica 分布在不同的机器上,这样才可以提⾼容错性。
这么搞,就有所谓的⾼可⽤性了,因为如果某个 broker 宕机了,没事⼉,那个 broker上⾯的 partition 在其他机器上都有副本的,如果这上⾯有某个 partition 的 leader,那么此时会从 follower 中重新选举⼀个新的 leader 出来,⼤家继续读写那个新的 leader 即可。这就有所谓的⾼可⽤性了。
写数据的时候,⽣产者就写 leader,然后 leader 将数据落地写本地磁盘,接着其他 follower ⾃⼰主动从 leader 来 pull 数据。⼀旦所有 follower 同步好数据了,就会发送 ack 给 leader,leader 收到所有 follower 的 ack 之后,就会返回写成功的消息给⽣产者。(当然,这只是其中⼀种模式,还可以适当调整这个⾏为)
消费的时候,只会从 leader 去读,但是只有当⼀个消息已经被所有 follower 都同步成功返回 ack 的时候,
这个消息才会被消费者读到。
看到这⾥,相信你⼤致明⽩了 Kafka 是如何保证⾼可⽤机制的了,对吧?不⾄于⼀⽆所知,现场还能给⾯试官画画图。要是遇上⾯试官确实是 Kafka ⾼⼿,深挖了问,那你只能说不好意思,太深⼊的你没研究过。
作者:2货我怕谁

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。