java面试总结----RabbitMQ篇

 

一.RabbitMQ结构

java面试总结----RabbitMQ篇_第1张图片

a. Broker:简单来说就是消息队列列服务器器实体。
b. Exchange:消息交换机,它指定消息按什什么规则,路路由到哪个队列。
c. Queue:消息队列列载体,每个消息都会被投入到一个或多个队列。
d. Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
e. Routing Key:路路由关键字,exchange根据这个关键字进行消息投递。
f. vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
g. producer:消息生产者,就是投递消息的程序。
h. consumer:消息消费者,就是接受消息的程序。
i. channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。 

二.RabbitMQ交换器器有哪些类型


1. fanout交换器器:它会把所有发送到该交换器器的消息路路由到所有与该交换器器绑定的队列中;
2. direct交换器器:direct类型的交换器器路路由规则很简单,它会把消息路路由到哪些BindingKey和RoutingKey完全匹配的队列中;
3. topic交换器器:匹配规则比direct更更灵活。
4. headers交换器器:根据发送消息内容的headers属性进行匹配(由于性能很差,不实用)。


常用的交换器主要分为以下三种:
1、direct:如果路由键完全匹配,消息就被投递到相应的队列
2、fanout:如果交换器收到消息,将会广播到所有绑定的队列上
3、topic:可以使来不同源头的消息能够到达同一个队列。 使用topic交换器时,可以使通配符,如:“*” 匹配特定位
置的任意文本, “.” 把路由键分为了几部分,“#” 匹配所有规则等。特别注意:发往topic交换器的消息不能随意的设置选择
键(routing_key),必须是由"."隔开的一系列的标识符组成。

 

三.RabbitMQ消息基于什什么传输


由于TCP连接的创建和销毁开销较⼤大,且并发数受系统资源限制,会造成性能瓶颈。RabbitMQ使用信道的方式来传输数
据。信道是建⽴立在真实的TCP连接内的虚拟连接,且每条TCP连接上的信道数量量没有限制。
1、RabbitMQ采⽤类似NIO(Non-blocking I/O)做法,选择TCP连接复用,不仅可以减少性能开销,同时也便于管理。
2、每个线程把持一个信道,所以信道服用了Connection的TCP连接。同时RabbitMQ可以确保每个线程的私密性,就像拥有独立的连接一样。

四.RabbitMQ消息怎么路由


从概念上来说,消息路路由必须有三部分:交换器器、路路由、绑定。生产者把消息发布到交换器器上;绑定决定了消息如何从交换器路由到特定的队列列;消息最终到达队列列,并被消费者接收。
1、消息发布到交换器器时,消息将拥有一个路路由键(routing key),在消息创建时设定。
2、通过路由键,可以把队列绑定到交换器上。
3、消息到达交换器后,RabbitMQ会将消息的路由键与队列列的路由键进行匹配(针对不同的交换器有不同的路由规则)。
4、如果能够匹配到队列列,则消息会投递到相应队列列中;如果不不能匹配到任何队列列,消息将进入 “黑洞”。

 

五.RabbitMQ如何保证数据一致性

 

  • 1. 生产者确认机制(confirm模式):消息持久化后异步回调通知生产者,保证消息已经发出去;
  • 2. 消息持久化:设置消息持久化;
  • 3. 消费者确认机制(ack机制):消费者成功消费消息之后,手动确认,保证消息已经消费。

1.RabbitMQ怎么保证生产者不丢失消息(confirm模式)

  1. 使用事务(不推荐)。发生异常就进行回滚,重新发送消息,存在问题:事务是同步机制,降低吞吐量。
  2. 使用confirm模式(推荐)。使用的是回调的机制,异步的模式,不会造成阻塞,生产者可以继续发送下一条消息,这样吞吐量不会受到影响。

2.RabbitMQ怎么保证MQ挂掉消息不丢失

开启持久化,就是消息写入后持久化到磁盘,哪怕是MQ挂掉也可以读取之前的持久化数据。

消息持久化的前提是:将交换器器/队列列的durable属性设置为true,表示交换器器/队列列是持久交换器器/队列列,在服务器器崩溃或重
启之后不不需要重新创建交换器器/队列列(交换器器/队列列会⾃自动创建)。
如果消息想要从Rabbit崩溃中恢复,那么消息必须:
1、在消息发布前,通过把它的 “投递模式” 选项设置为2(持久)来把消息标记成持久化
2、将消息发送到持久交换器器
3、消息到达持久队列列
RabbitMQ确保持久性消息能从服务器重启中恢复的方式是,将它们写入磁盘上的一个持久化日志文件,当发布一条
持久性消息到持久交换器上时,Rabbit会在消息提交到日志文件后才发送响应(如果消息路由到了非持久队列,它会自动
从持久化日志中移除)。一旦消费者从持久队列中消费了一条持久化消息,RabbitMQ会在持久化日志中把这条消息标记为
等待垃圾收集。如果持久化消息在被消费之前RabbitMQ重启,那么Rabbit会自动重建交换器和队列(以及绑定),并重播
持久化日志文件中的消息到合适的队列或者交换器上

3.RabbitMQ怎么保证消费者不丢失消息(即消费者消费成功了消息)

关闭消费者的autoAck机制,消费者通过自己判断消息是否处理完成,处理完成后发送ack给MQ

接收方消息确认机制:消费者接收每一条消息后都必须进行ack确认(消息接收和消息确认是两个不不同操作)。只有消费者确
认了了消息,RabbitMQ才能安全地把消息从队列列中删除。
这里并没有用到超时机制,RabbitMQ仅通过Consumer的连接中断来确认是否需要重新发送消息。也就是说,只要连接不不
中断,RabbitMQ给了了Consumer足够长的时间来处理理消息。
特殊情况:
1、如果消费者接收到消息,在确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被分发,然后重新分发给下一
个订阅的消费者。(可能存在消息重复消费的隐患,需要根据bizId去重)
2、如果消费者接收到消息却没有确认消息,连接也未断开,则RabbitMQ认为该消费者繁忙,将不会给该消费者分发更多
的消息。

六.如何避免消息重复投递或重复消费?


在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重和幂等的依据(消息投递失败并重
传),避免重复的消息进入队列列;在消息消费时,要求消息体中必须要有一个bizId(对于同一业务全局唯一,如支付ID、订单ID、帖子ID等)作为去重和幂等的依据,避免同一条消息被重复消费。

七.RabbitMQ怎么解决消息积压问题

情景:消费者挂掉后再重启,这时会有很多已经挤压了的消息在MQ中,所以需要快速的处理之前已经挤压了的消息。
解决方案:可以将原由的消费者进行修改,不再直接对数据库进行操作,只对MQ的数据进行并将处理得到的数据再发给新的partition(可以创建很多来进行过度),然后再由很多消费者进行同时的消费,并写入数据库。这是处理速度就会很快。因为第一次的消费者处理之后并不用写入数据库就可以给MQ反馈已经消费了;后续的消费者继续处理需要消费的数据并不会影响之前的消费者处理的速度。
 

你可能感兴趣的:(RabbitMQ)