java⾯试题总结(六)--消息队列MQ-⾯试题
⽬录
1.什么是消息队列?
可以看作是⼀个存放消息的容器,当我们需要使⽤消息的时候可以取出消息供⾃⼰使⽤。消息队列是分布式系统中重要的组件,使⽤消息队列主要是为了通过异步处理提⾼系统性能和削峰、降低系统耦合性。⽬前使⽤较多的消息队列有
matlab获取图像中图形坐标ActiveMQ,RabbitMQ,Kafka,RocketMQ。
通过提供 消息传递 和 消息排队 模型,它可以在 分布式环境 下提供 应⽤解耦、弹性伸缩、冗余存储、流量削峰、异步通信、数据同步 等等功能。
消息队列容易和 Java 中的本地 MessageQueue 搞混,所以消息队列更多被称为消息中间件、分布式消息队列等等。
2.为什么要使⽤消息队列?
1 解耦
消息队列使利⽤发布-订阅模式⼯作,消息发送者(⽣产者)发布消息,⼀个或多个消息接受者(消费者)订阅消息。消息发送者(⽣产者)和消息接受者(消费者)之间没有直接耦合,消息发送者将消息发送⾄分布式消息队列即结束对消息的处理,消息接受者从分布式消息队列获取该消息后进⾏后续处理,并不需要知道该消息从何⽽来。
消息接受者对消息进⾏过滤、处理、包装后,构造成⼀个新的消息类型,将消息继续发送出去,等待其他消息接受者订阅该消息。因此基于事件(消息对象)驱动的业务架构可以是⼀系列流程。
另外为了避免消息队列服务器宕机造成消息丢失,会将成功发送到消息队列的消息存储在消息⽣产者服务器上,等消息真正被消费者服务器处理后才删除消息。在消息队列服务器宕机后,⽣产者服务器会选择分布式消息队列服务器集中的其他服务器发布消息。
不要认为消息队列只能利⽤发布-订阅模式⼯作,只不过在解耦这个特定业务环境下是使⽤发布-订阅模式的。除了发布-订阅模式,还有点对点订阅模式(⼀个消息只有⼀个消费者),我们⽐较常⽤的是发布-订阅模式。 另外,这两种消息模型是 JMS 提供的,AMQP 协议还提供了 5 种消息模型。
2 异步处理、
传统模式中⼀些⾮必要的业务逻辑以同步的⽅式运⾏,太耗费时间。使⽤消息队列之后,⽤户的请求数据发送给消息队列之后⽴即 返回,再由消息队列的消费者进程从消息队列中获取数据,异步写⼊数据库。由于消息队列服务器处理速度快于数据库(消息队列也⽐数据库有更好的伸缩性),因此响应
mysql面试题常问速度得到⼤幅改善。
3 削峰
消息队列具有很好的削峰作⽤——即通过异步处理,将短时间⾼并发产⽣的事务消息存储在消息队列中,从⽽削平⾼峰期的并发事务。
3.使⽤消息队列带来的⼀些问题
系统可⽤性降低: 在加⼊MQ之前,需要考虑消息丢失或者说MQ挂掉等等的情况。
系统复杂性提⾼: 加⼊MQ之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题!
⼀致性问题: 消息队列可以实现异步,消息队列带来的异步确实可以提⾼系统响应速度。但是,万⼀消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不⼀致的情况了!
4.JMS两种消息模型
fontcreator14版①点到点(P2P)模型
使⽤队列(Queue)作为消息通信载体;满⾜⽣产者与消费者模式,⼀条消息只能被⼀个消费者使⽤,未被消费的消息在队列中保留直到被消费或超时。⽐如:我们⽣产者发送100条消息的话,两个消费者来消费⼀般情况下两个消费者会按照消息发送的顺序各⾃消费⼀半(也就是你⼀个我⼀个的消费。)
② 发布/订阅(Pub/Sub)模型gridview控件怎么获取编辑列中的选择和删除
发布订阅模型(Pub/Sub) 使⽤主题(Topic)作为消息通信载体,类似于⼴播模式;发布者发布⼀条消息,该消息通过主题传递给所有的订阅者,在⼀条消息⼴播之后才订阅的⽤户则是收不到该条消息的。
MQ ⾓⾊
1. 拉取(Pull),是指 Consumer 主动从 Message Broker 获取消息
2. 推送(Push),是指 Message Broker 主动将 Consumer 感兴趣的消息推送给 Consumer 。
Topic
主题,发布订阅模式下的消息统⼀汇集地,不同⽣产者向topic发送消息,由MQ服务器分发到不同的订阅者,实现消息的⼴播Queue
队列,PTP模式下,特定⽣产者向特定queue发送消息,消费者订阅特定的queue完成指定消息的接收
6.常见消息中间件⽐较
(1)中⼩型软件公司,建议选RabbitMQ.⼀⽅⾯,erlang语⾔天⽣具备⾼并发的特性,⽽且他的管理界⾯⽤起来⼗分⽅便。正所谓,成
也萧何,败也萧何!他的弊端也在这⾥,虽然RabbitMQ是开源的,然⽽国内有⼏个能定制化开发erlang的程序员呢?所
幸,RabbitMQ的社区⼗分活跃,可以解决开发过程中遇到的bug,这点对于中⼩型公司来说⼗分重要。不考虑rocketmq和kafka的原因是,⼀⽅⾯中⼩型软件公司不如互联⽹公司,数据量没那么⼤,选消息中间件,应⾸选功能⽐较完备的,所以kafka排除。不考虑rocketmq的原因是,rocketmq是阿⾥出
品,如果阿⾥放弃维护rocketmq,中⼩型公司⼀般抽不出⼈来进⾏rocketmq的定制化开发,因此不推荐。
(2)⼤型软件公司,根据具体使⽤在rocketMq和kafka之间⼆选⼀。⼀⽅⾯,⼤型软件公司,具备⾜够的资⾦搭建分布式环境,也具备
⾜够⼤的数据量。针对rocketMQ,⼤型软件公司也可以抽出⼈⼿对rocketMQ进⾏定制化开发,毕竟国内有能⼒改JAVA源码的⼈,还是相当多的。⾄于kafka,根据业务场景选择,如果有⽇志采集功能,肯定是⾸选kafka了。具体该选哪个,看使⽤场景。
7.多个条件if函数公式
RocketMQ
1. Producer
1、Producer ⾃⾝在应⽤中,所以⽆需考虑⾼可⽤。
2、Producer 配置多个 Namesrv 列表,从⽽保证 Producer 和 Namesrv 的连接⾼可⽤。并且,会从 Namesrv 定时拉取
最新的 Topic 信息。
3、Producer 会和所有 Consumer 直连,在发送消息时,会选择⼀个 Broker 进⾏发送。如果发送失败,则会使⽤另外⼀
个 Broker 。
4、Producer 会定时向 Broker ⼼跳,证明其存活。⽽ Broker 会定时检测,判断是否有 Producer 异常下线。
2. Consumer
1、Consumer 需要部署多个节点,以保证 Consumer ⾃⾝的⾼可⽤。当相同消费者分组中有新的 Consumer 上线,或者
⽼的 Consumer 下线,会重新分配 Topic 的 Queue 到⽬前消费分组的 Consumer 们。
2、Consumer 配置多个 Namesrv 列表,从⽽保证 Consumer 和 Namesrv 的连接⾼可⽤。并且,会从 Consumer 定时
拉取最新的 Topic 信息。
3、Consumer 会和所有 Consumer 直连,消费相应分配到的 Queue 的消息。如果消费失败,则会发回消息到 Broker
中。
4、Consumer 会定时向 Broker ⼼跳,证明其存活。⽽ Broker 会定时检测,判断是否有 Consumer 异常下线。
3. Namesrv
1、Namesrv 需要部署多个节点,以保证 Namesrv 的⾼可⽤。
2、Namesrv 本⾝是⽆状态,不产⽣数据的存储,是通过 Broker ⼼跳将 Topic 信息同步到 Namesrv 中。
3、多个 Namesrv 之间不会有数据的同步,是通过 Broker 向多个 Namesrv 多写。
4. Broker
1、多个 Broker 可以形成⼀个 Broker 分组。每个 Broker 分组存在⼀个 Master 和多个 Slave 节点。
Master 节点,可提供读和写功能。Slave 节点,可提供读功能。
Master 节点会不断发送新的 CommitLog 给 Slave节点。Slave 节点不断上报本地的 CommitLog 已经同步到的位置给
Master 节点。
Slave 节点会从 Master 节点拉取消费进度、Topic 配置等等。
2、多个 Broker 分组,形成 Broker 集。
ubuntu离线安装gccBroker 集和集之间,不存在通信与数据同步。
3、Broker 可以配置同步刷盘或异步刷盘,根据消息的持久化的可靠性来配置。
kafka
Zookeeper 部署 2N+1 节点,形成 Zookeeper 集,保证⾼可⽤。
Kafka Broker 部署集。
每个 Topic 的 Partition ,基于【副本机制】,在 Broker 集中复制,形成 replica 副本,保证消息存储的可靠性。每个 replica 副本,都会选择出⼀个 leader 分区(Partition),提供给客户端(Producer 和 Consumer)进⾏读写(只能读写 leader)。
Kafka Producer ⽆需考虑集,因为和业务服务部署在⼀起。Producer 从 Zookeeper 拉取到 Topic 的元数据后,选择对应的Topic 的 leader 分区,进⾏消息发送写⼊。⽽ Broker 根据 Producer 的 quired.acks 配置,是写⼊⾃⼰完成就响应给Producer 成功,还是写⼊所有 Broker 完成再响应。这个,就是胖友⾃⼰对消息的可靠性的选择。
Kafka Consumer 部署集。每个 Consumer 分配其对应的 Topic Partition ,根据对应的分配策略。并且,Consumer 只从leader 分区(Partition)拉取消息。另外,当有新的 Consumer 加⼊或者⽼的 Consumer 离开,都会将 Topic Partition 再均衡,重新分配给 Consumer 。
写数据的时候,⽣产者就写 leader,然后 leader 将数据落地写本地磁盘,接着其他 follower ⾃⼰主动从 leader 来 pull 数据。
⼀旦所有 follower 同步好数据了,就会发送 ack 给 leader,leader 收到所有 follower 的 ack 之后,就会返回写成功的消息给⽣产者。(当然,这只是其中⼀种模式,还可以适当调整这个⾏为)
消费的时候,只会从 leader 去读,但是只有当⼀个消息已经被所有 follower 都同步成功返回 ack 的时候,这个消息才会被消费者读到。
8.如何保证消息不被重复消费(幂等性)
回答这个问题,⾸先你别听到重复消息这个事⼉,就⼀⽆所知吧,你先⼤概说⼀说可能会有哪些重复消费的问题。
⾸先,⽐如 RabbitMQ、RocketMQ、Kafka,都有可能会出现消息重复消费的问题,正常。因为这问题通常不是 MQ ⾃⼰保证的,是由我们开发来保证的。挑⼀个 Kafka 来举个例⼦,说说怎么重复消费吧。
Kafka 实际上有个 offset 的概念,就是每个消息写进去,都有⼀个 offset,代表消息的序号,然后 consumer 消费了数据之后,每隔⼀段时间(定时定期),会把⾃⼰消费过的消息的 offset 提交⼀下,表⽰“我已经消费过了,下次我要是重启啥的,你就让我继续从上次消费到的 offset 来继续消费吧”。
但是凡事总有意外,⽐如我们之前⽣产经常遇到的,就是你有时候重启系统,看你怎么重启了,如果碰到点着急的,直接 kill 进程了,再重启。这会导致 consumer 有些消息处理了,但是没来得及提交 offset,尴尬了。重启之后,少数消息会再次消费⼀次。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论