• 消息队列面试题


    RabbitMQ的构造

    RabbitMQ 是 AMQP 协议的一个开源实现

     

    (1)生产者Publisher:生产消息,就是投递消息的一方
    (2)消费者Consumer:消费消息,也就是接收消息的一方
    (3)Broker服务节点:表示消息队列服务器
    (4)Queue:消息队列,用来存放消息
    (5)Exchange:交换器,接受生产者发送的消息,根据路由键将消息路由到绑定的队列上
    (6)Routing Key: 路由关键字,用于指定这个消息的路由规则
    (7)Binding:绑定,通过绑定将交换器和队列关联起来,一般会指定一个BindingKey
    (8)Connection :TCP网络连接
    (9)Channel: 信道,AMQP 命令都是在信道中进行的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接,一个TCP连接可以用多个信道。客户端可以建立多个channel,每个channel表示一个会话任务。
    (10)Message:消息,由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。
    (11)Virtual host:虚拟主机,用于逻辑隔离,表示一批独立的交换器、消息队列和相关对象。一个Virtual host可以有若干个Exchange和Queue,同一个Virtual host不能有同名的Exchange或Queue。最重要的是,其拥有独立的权限系统,可以做到 vhost 范围的用户控制。当然,从 RabbitMQ 的全局角度,vhost 可以作为不同权限隔离的手段

    Exchange交换器的类型

    fanout:把所有发送到fanout交换器的消息路由到所有绑定该交换器的队列中,fanout 类型转发消息是最快的。

    direct:消息中的路由键(RoutingKey)如果和 Bingding 中的 bindingKey 完全匹配,交换器就将消息发到对应的队列中。是基于完全匹配。

    topic:通过模式匹配的方式对消息进行路由,支持多个RoutinKey单词,支持通配符匹配

    通配符规则:

    #:匹配一个或多个词

    *:匹配不多不少恰好1个词

    BindingKey和RoutingKey区别

    BindingKey 可以使用通配符,用于绑定交换机和队列

    RoutingKey 具体匹配,如:发送消息需要指定具体key

    生产者消息的过程

    (1)Producer 先连接到 Broker,建立TCP连接 Connection,开启一个信道 channel
    (2)Producer 声明交换器和队列并通过BindingKey绑定在一起,fanout忽略bingingKey
    (3)Producer 发送消息到 Broker,其中包含路由键、交换器等信息
    (4)交换器根据接收到的路由键查找匹配的队列
    (5)如果找到,将消息存入对应的队列,如果没有找到,会根据生产者的配置丢弃或者退回给生产者
    (6)关闭信道

    消费者接收消息过程 

    (1)Producer 先连接到 Broker,建立TCP连接 Connection,开启一个信道 channel
    (2)向 Broker 请求消费相应队列中消息,可能会设置响应的回调函数。
    (3)等待 Broker 回应并投递相应队列中的消息,接收消息。
    (4)消费者确认收到的消息,ack。
    (5)RabbitMQ从队列中删除已经确定的消息。
    (6)关闭信道

    消息队列的优缺点

    优点:解耦、异步、削峰

    缺点:系统可用性降低、系统复杂度提高、一致性问题

    如何保证消息队列的高可用

    RabbitMQ搭建模式有:

    单机模式:生产环境没人用
    普通集群模式:
    普通集群模式用于提高系统的吞吐量
    队列的消息只会存放在其中一个 RabbitMQ 实例上,但是每个实例都同步 queue 的元数据(元数据是 queue 的一些配置信息,通过元数据,可以找到 queue 所在实例)。
    消费的时候,如果连接到了另外的实例,那么该实例就会从数据实际所在的实例上的queue拉取消息过来,就是说让集群中多个节点来服务某个 queue 的读写操作。
    普通集群模式的缺点在于:无高可用性,queue所在的节点宕机了,其他实例就无法从那个实例拉取数据;RabbitMQ 内部也会产生大量的数据传输。

    镜像集群模式高可用:

    创建的 queue,无论元数据还是 queue 里的消息都会存在于多个实例上

    那么如何开启这个镜像集群模式呢?RabbitMQ 有很好的管理控制台,就是在后
    台新增一个策略,这个策略是镜像集群模式的策略,指定的时候是可以要求数据同步到所有
    节点的,也可以要求同步到指定数量的节点,再次创建 queue 的时候,应用这个策略,就会自
    动将数据同步到其他的节点上去了。
    仲裁队列

    如何确保消息的可靠性

    消息可靠性传输分析由三部分组成:生产者丢数据、消息队列丢数据、消费者丢数据

    1.生产者丢数据:

    RabbitMQ提供事务机制(transaction)和确认机制(confirm)两种模式来确保生产者不丢消息。

    2.消息队列丢数据:

    处理消息队列丢数据的情况,一般是开启持久化磁盘。持久化配置可以和生产者的 confirm 机制配合使用,在消息持久化磁盘后,再给生产者发送一个Ack信号。这样的话,如果消息持久化磁盘之前,即使 RabbitMQ 挂掉了,生产者也会因为收不到Ack信号而再次重发消息。

    3.消费者丢数据

    解决方案就是采用手动确认消息,设置 autoAck = False,等到消息被真正消费之后,再手动发送一个确认信号,即使中途消息没处理完,但是服务器宕机了,那 RabbitMQ 就收不到发的ack,然后 RabbitMQ 就会将这条消息重新分配给其他的消费者去处理。

    开启生产者确认机制

    开启持久化功能

    开启消费者手动确认机制

    开启消费者失败重试机制,多次重试失败后将消息投递到异常交换机,交由人工处理

    如何保证消息没有重复消费

    重复消费问题的解决思路是:保证消息的唯一性,即使多次传输,也不让消息的多次消费带来影响,也就是保证消息等幂性;幂等性指一个操作执行任意多次所产生的影响均与一次执行的影响相同。

    1. 造业务逻辑,使得在重复消费时也不影响最终的结果。例如对SQL语句: update t1 set money = 150 where id = 1 and money = 100; 做了个前置条件判断,即 money = 100 的情况下才会做更新,更通用的是做个 version 即版本号控制,对比消息中的版本号和数据库中的版本号。
    2. 基于数据库的的唯一主键进行约束。消费完消息之后,到数据库中做一个 insert 操作,如果出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。
    3. 通过记录关键的key,当重复消息过来时,先判断下这个key是否已经被处理过了,如果没处理再进行下一步。

    消息堆积问题

     惰性队列优缺点

     优点:

     缺点:

    可靠消息最终一致性需要解决的问题  

    • 上游服务把信息成功发送
    • 下游服务成把消息成功消费
    • 对消息做幂等
    • 失败重试,死信队列,人工干预。

    KafkaActiveMQRabbitMQRocketMQ 区别

  • 相关阅读:
    ES6 入门教程 21 async 函数 21.1 含义 & 21.2 基本用法
    Oracle中分割字符串的方法
    vue+Ts+element组件封装
    python传参时一个星号和两个星号的区别
    MySQL开机无法启动,需手动启动才可以。
    vue通过vant列表实现下拉到底部加载更多列表数据
    Haddop集群的简单搭建
    运行springBoot项目
    到此一游︱2022 Google 开发者大会
    tomcat类加载-源码解析
  • 原文地址:https://blog.csdn.net/qq_29385297/article/details/126800858