面试喜欢问消息队列,特别是大厂
我们都知道队列,一端入队,一端出队。消息队列也是类似的结构,一端生产者只负责往队列里发送消息数据,另一端消费者只负责从队列里获取数据,获取方式可能是队列推送或者消费者拉取
对于以下同步的操作,时间t=t(用户注册)+t(注册写入)+t(发送注册邮件)+t(发送注册短信)
如果使用消息队列来异步发送,时间t=t(用户注册)+t(注册写入)+max(t(发送注册邮件), t(发送注册短信)),之前是同步发送,现在发送的事情交给消息队列来处理
削峰其实就是请求太多了,一下子处理不完,甚至可能太多请求压垮服务器或者数据库,例如双十一,亿级的请求,50w的qps如果直接打在数据库,基本宕机了,但是如果使用消息队列存放,消费者用可以接受的最快速度进行消费就行了,然后过了峰值时间,消费者最后会消费完所有数据。
再比如使用RocketMQ,有一个点赞业务,不限制用户的点赞数只需进行记录(产品需求,开发提议无效),当每个用户都进行x连击享受数量猛增的快感时如果数据库都需要进行x个点赞数据的插入,数据库毫无疑问会塞死导致崩溃。
于是想到可以尝试下MQ削峰,比如每秒来了5000消息但数据库只能承受2000,那我消费时每次只拉取消费1600就好了,剩下的放在Broker堆积慢慢消费就好。由于之前的消息中心也在用RocketMQ,于是确认使用RocketMQ来进行削峰。
举个例子,A公司做了某个系统,B公司觉得A公司的某个功能很好,于是B公司和A公司的系统进行了集成。这时C公司也觉得A公司的这个功能很好,于是,C公司也和A公司的系统进行了集成。以后还有D公司…。
介于这种情况,A公司的系统和其他公司的耦合度都很高,每集成一个公司的系统,A公司都需要修改自己的系统。如果采用消息队列,则变成了如下:
不管以后还有多少公司的应用程序想要用A公司的程序,都不需要和A公司进行集成,谁需要这个功能,谁就去消息队列里面获取
对于消息队列里的消息,可能有重复的,可能消息会在入队时丢失,也可能就是刚好消费一次
该场景是最容易满足的,特点是整个消息队列吞吐量大,实现简单。适合能容忍丢消息,消息重复消费的任务。
适合不能容忍丢消息,但允许重复消费的任务。
秒杀活动,双十一削峰,点赞数更新等
目前在市面上比较主流的消息队列中间件主要有,Kafka、ActiveMQ、RabbitMQ、RocketMQ 等这几种。
ActiveMQ和RabbitMQ这两着因为吞吐量还有GitHub的社区活跃度的原因,在各大互联网公司都已经基本上绝迹了,业务体量一般的公司会是有在用的,但是越来越多的公司更青睐RocketMQ这样的消息中间件了。
Kafka和RocketMQ一直在各自擅长的领域发光发亮,目前用的比较多
至于各个组件之间的区别,如下图:
RabbitMQ的高可用是基于主从(非分布式)做高可用性。RabbitMQ 有三种模式:单机模式(Demo级别)、普通集群模式(无高可用性)、镜像集群模式(高可用性)。
就是多机部署多个RabbitMQ实例,每个机器上运行一个实例,但是真正保存消息队列的只有一台机器上的一个实例,其他实例保存的是消息队列的元数据,其他机器可以从主实例拉取消息然后返回。所以整个集群只有一个消息队列,但是可以多台机器访问,看起来只是提高了吞吐量。
这个模式才是真正的高可用,每个机器也是一个实例,但是实例都保存同一个消息队列,相当于一个消息队列有多个备份,所以主要压力时生产者需要同步所有实例,所以网络带宽压力更大了。
Kafka的天然架构就是适合分布式的,Kafka 一个最基本的架构认识:由多个 broker 组成,每个 broker 是一个节点;你创建一个 topic,这个 topic 可以划分为多个 partition,每个 partition 可以存在于不同的 broker 上,每个 partition 就放一部分数据。
Kafka 0.8 以后,提供了 HA 机制,就是 replica(复制品) 副本机制。每个 partition 的数据都会同步到其它机器上,形成自己的多个 replica 副本。所有 replica 会选举一个 leader 出来,那么生产和消费都跟这个 leader 打交道,然后其他 replica 就是 follower。写的时候,leader 会负责把数据同步到所有 follower 上去,读的时候就直接读 leader 上的数据即可。只能读写 leader?很简单,要是你可以随意读写每个 follower,那么就要 care 数据一致性的问题,系统复杂度太高,很容易出问题。Kafka 会均匀地将一个 partition 的所有 replica 分布在不同的机器上,这样才可以提高容错性。
如果某个 broker 宕机了,那个 broker上面的 partition 在其他机器上都有副本的。如果这个宕机的 broker 上面有某个 partition 的 leader,那么此时会从 follower 中重新选举一个新的 leader 出来,大家继续读写那个新的 leader 即可。这就有所谓的高可用性了。
写数据的时候,生产者就写 leader,然后 leader 将数据落地写本地磁盘,接着其他 follower 自己主动从 leader 来 pull 数据。一旦所有 follower 同步好数据了,就会发送 ack 给 leader,leader 收到所有 follower 的 ack 之后,就会返回写成功的消息给生产者。(当然,这只是其中一种模式,还可以适当调整这个行为)
消费的时候,只会从 leader 去读,但是只有当一个消息已经被所有 follower 都同步成功返回 ack 的时候,这个消息才会被消费者读到。
这里转发一下知乎的高赞回答,由于篇幅问题,我将搬运在另一篇文章
https://mp.weixin.qq.com/s/8prxhEfcc4b3RFBjFLhk9g https://cloud.tencent.com/developer/article/1629610 https://www.zhihu.com/question/34243607 https://juejin.cn/post/6844903993081085965