2022年后端面试必读秘籍(分类导读面试-中间件篇)

前言

飓哥今天给大家带来2022年面试必看题目及答案(中间件篇),希望大家喜欢

码字不易,小伙伴们觉得有帮助的话,点个赞呗 你的赞就是我创作的动力!

我是 @飓哥,经常会分享Java后台硬核知识,欢迎大家关注~

1.activemq 的几种通信方式

publish(发布)-subscribe(订阅)(发布-订阅方式)

发布/订阅方式用于多接收客户端的方式.作为发布订阅的方式,可能存在多个

接收客户端,并且接收端客户端与发送客户端存在时间上的依赖。一个接收端

只能接收他创建以后发送客户端发送的信息。作为 subscriber ,在接收消息时

有两种方法,destination 的 receive 方法,和实现 message listener 接口的

onMessage 方法


p2p(point-to-point)(点对点)

p2p 的过程则理解起来比较简单。它好比是两个人打电话,这两个人是独享这

一条通信链路的。一方发送消息,另外一方接收,就这么简单。在实际应用中

因为有多个用户对使用 p2p 的链路。

在 p2p 的场景里,相互通信的双方是通过一个类似于队列的方式来进行交流。

和前面 pub-sub 的区别在于一个 topic 有一个发送者和多个接收者,而在 p2p

里一个 queue 只有一个发送者和一个接收者。

 

2. activemq 如果数据提交不成功怎么办(消息丢失)

1. publish(发布)-subscribe(订阅)方式的处理

发布订阅模式的通信方式, 默认情况下只通知一次, 如果接收不到此消息就没

有了。 这种场景只适用于对消息送达率要求不高的情况。 如果要求消息必须送

达不可以丢失的话, 需要配置持久订阅。 每个订阅端定义一个 id

2.点对点模式的话, 如果消息发送不成功此消息默认会保到 activemq 服

务端直到有消费者将其消费, 所以此时消息是不会丢失的。

3.如何解决消息重复问题

所谓消息重复,就是消费者接收到了重复的消息,一般来说我们对于这个问题的处

理要把握下面几点, ①.消息不丢失(上面已经处理了) ②.消息不重复执行

一般来说我们可以在业务段加一张表,用来存放消息是否执行成功,每次业务事物

commit 之后,告知服务端,已经处理过该消息, 这样即使你消息重发了,也不会导致重复处理.

大致流程如下:

业务端的表记录已经处理消息的 id,每次一个消息进来之前先判断该消息
是否执行过,如果执行过就放弃,如果没有执行就开始执行消息,消息执行完成之
后存入这个消息的 id

4.大量的消息每页被消费,能否发生 oom 异常?

可以控制每个消息队列中数据的大小,不允许无线填充数据,避免该队列多

大,导致过度消耗系统资源问题; 可以控制队列的内存大小;

5.activeMQ 发送消息的方式有哪些?

消息通信的基本方式有两种:

1、同步方式

两个通信应用服务之间必须要进行同步,两个服务之间必须都是正常运行的。

发送程序和接收程序都必须一直处于运行状态,并且随时做好相互通信的准

备。

发送程序首先向接收程序发起一个请求,称之为发送消息,发送程序紧接着就

会堵塞当前自身的进程,不与其他应用进行任何的通信以及交互,等待接收程

序的响应,待发送消息得到接收程序的返回消息之后会继续向下运行,进行下

一步的业务处理。

2、异步方式

两个通信应用之间可以不用同时在线等待,任何一方只需各自处理自己的业

务,比如发送方发送消息以后不用登录接收方的响应,可以接着处理其他的任

务。也就是说发送方和接收方都是相互独立存在的,发送方只管方,接收方只

能接收,无须去等待对方的响应。

Java 中 JMS 就是典型的异步消息处理机制,JMS 消息有两种类型:点对点、

发布/订阅

6. activeMQ 如何调优

1. 使用非持久化消息;

2. 需要确保消息发送成功时使用事务来将消息分批组合.

public void sendTransacted() throws JMSException { ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(); Connection connection = cf.createConnection(); connection.start(); Session session = connection.createSession(true, Session.SESSION_TRANSACTED); Topic topic = session.createTopic("Test.Transactions"); MessageProducer producer = session.createProducer(topic); int count = 0; for (int i = 0; i < 1000; i++) { Message message = session.createTextMessage("message " + i); producer.send(message); if (i != 0 && i % 10 == 0) { session.commit(); } } } public void sendNonTransacted() throws JMSException { ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(); Connection connection = cf.createConnection(); connection.start(); // create a default session (no transactions) Session session = connection.createSession(false, Session.AUTO_ACKNOWELDGE); Topic topic = session.createTopic("Test.Transactions"); MessageProducer producer = session.createProducer(topic); int count = 0; for (int i = 0; i < 1000; i++) { Message message = session.createTextMessage("message " + i); producer.send(message); } }

 

7.什么是死信队列?

如果你想在消息处理失败后,不被服务器删除,还能被其他消费者处理或重

试,可以关闭 AUTO_ACKNOWLEDGE,将 ack 交由程序自己处理。那如果使

用了 AUTO_ACKNOWLEDGE,消息是什么时候被确认的,还有没有阻止消息

确认的方法?有!

消费消息有 2 种方法,一种是调用 consumer.receive()方法,该方法将阻塞直

到获得并返回一条消息。这种情况下,消息返回给方法调用者之后就自动被确

认了。另一种方法是采用 listener 回调函数,在有消息到达时,会调用

listener 接口的 onMessage 方法。在这种情况下,在 onMessage 方法执行

完毕后,消息才会被确认,此时只要在方法中抛出异常,该消息就不会被确

认。那么问题来了,如果一条消息不能被处理,会被退回服务器重新分配,如

果只有一个消费者,该消息又会重新被获取,重新抛异常。就算有多个消费

者,往往在一个服务器上不能处理的消息,在另外的服务器上依然不能被处

理。难道就这么退回--获取--报错死循环了吗?

在重试 6 次后,ActiveMQ 认为这条消息是“有毒”的,将会把消息丢到死信

队列里。如果你的消息不见了,去 ActiveMQ.DLQ 里找找,说不定就躺在那

里。

8.Basic.Reject 的用法是什么?

答:该信令可用于 consumer 对收到的 message 进行 reject 。若在该信令

中设置 requeue=true,则当 RabbitMQ server 收到该拒绝信令后,会将该

message 重新发送到下一个处于 consume 状态的 consumer 处(理论上

仍可能将该消息发送给当前 consumer)。若设置 requeue=false ,则

RabbitMQ server 在收到拒绝信令后,将直接将该 message 从 queue 中

移除。

另外一种移除 queue 中 message 的小技巧是,consumer 回复 Basic.Ack

但不对获取到的 message 做任何处理。

而 Basic.Nack 是对 Basic.Reject 的扩展,以支持一次拒绝多条 message

的能力。

9.为什么不应该对所有的 message 都使用持久化机制?

答:首先,必然导致性能的下降,因为写磁盘比写 RAM 慢的多,message

的吞吐量可能有 10 倍的差距。其次,message 的持久化机制用在

RabbitMQ 的内置 cluster 方案时会出现“坑爹”问题。矛盾点在于,若

message 设置了 persistent 属性,但 queue 未设置 durable 属性,那么

当该 queue 的 owner node 出现异常后,在未重建该 queue 前,发往该

queue 的 message 将被 blackholed ;若 message 设置了 persistent

属性,同时 queue 也设置了 durable 属性,那么当 queue 的 owner

node 异常且无法重启的情况下,则该 queue 无法在其他 node 上重建,只

能等待其 owner node 重启后,才能恢复该 queue 的使用,而在这段时间

内发送给该 queue 的 message 将被 blackholed 。

所以,是否要对 message 进行持久化,需要综合考虑性能需要,以及可能遇到的问题。若想

达到 100,000 条/秒以上的消息吞吐量(单 RabbitMQ 服务器),则要么使

用其他的方式来确保 message 的可靠 delivery ,要么使用非常快速的存储

系统以支持全持久化(例如使用 SSD)。另外一种处理原则是:仅对关键消息

作持久化处理(根据业务重要程度),且应该保证关键消息的量不会导致性能

瓶颈。

10.为什么 heavy RPC 的使用场景下不建议采用 disk node ?

答:heavy RPC 是指在业务逻辑中高频调用 RabbitMQ 提供的 RPC 机制, 导致不断创建、销毁 reply queue ,进而造成 disk node 的性能问题(因为 会针对元数据不断写盘)。所以在使用 RPC 机制时需要考虑自身的业务场 景。
 

11.向不存在的 exchange 发 publish 消息会发生什么?向不存在的queue 执行 consume 动作会发生什么?

答:都会收到 Channel.Close 信令告之不存在(内含原因 404
NOT_FOUND)

12.什么情况下 producer 不主动创建 queue 是安全的?

答:1.message 是允许丢失的;2.实现了针对未处理消息的 republish 功能 (例如采用 Publisher Confirm 机制)。

13. “dead letter”queue 的用途?

答:当消息被 RabbitMQ server 投递到 consumer 后,但 consumer 却通 过 Basic.Reject 进行了拒绝时(同时设置 requeue=false),那么该消息会 被放入“dead letter”queue 中。该 queue 可用于排查 message 被 reject 或 undeliver 的原因

14.为什么说保证 message 被可靠持久化的条件是 queue 和 exchange

答:binding 关系可以表示为 exchange – binding – queue 。从文档中我 们知道,若要求投递的 message 能够不丢失,要求 message 本身设置 persistent 属性,要求 exchange 和 queue 都设置 durable 属性。其实这 问题可以这么想,若 exchange 或 queue 未设置 durable 属性,则在其 crash 之后就会无法恢复,那么即使 message 设置了 persistent 属性,仍 然存在 message 虽然能恢复但却无处容身的问题;同理,若 message 本身 未设置 persistent 属性,则 message 的持久化更无从谈起。

 

码字不易,小伙伴们觉得有帮助的话,点个赞呗 你的赞就是我创作的动力!

我是 @飓哥,经常会分享Java后台硬核知识,欢迎大家关注~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飓哥聊IT人生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值