美文网首页
常见面试

常见面试

作者: 指尖架构141319 | 来源:发表于2019-12-05 15:56 被阅读0次

    1.消息重复可能的原因

    1.1第一类原因

    消息 发送端 应用的消息重复发送,有以下几种情况:

    • 消息发送端发送消息给消息中间件,消息中间件收到消息并成功存储,而这时消息中间件出现了问题,导致应用端没有收到消息发送成功的返回因而进行重试产生了重复。
    • 消息中间件因为负载高响应变慢,成功把消息存储到消息存储中后,返回“成功”这个结果时超时。
    • 消息中间件将消息成功写入消息存储,在返回结果时网络出现问题,导致应用发送端重试,而重试时网络恢复,由此导致重复。
    1.2 第二类原因

    消息到达了消息存储,由消息中间件进行向外的投递时产生重复,有以下几种情况:

    • 消息被投递到消息接收者应用进行处理,处理完毕后应用出问题了,消息中间件不知道消息处理结果,会再次投递。
    • 消息被投递到消息接收者应用进行处理,处理完毕后网络出现问题了,消息中间件没有收到消息处理结果,会再次投递。
    • 消息被投递到消息接收者应用进行处理,处理时间比较长,消息中间件因为消息超时会再次投递。
    • 消息被投递到消息接收者应用进行处理,处理完毕后消息中间件出问题了,没能收到消息结果并处理,会再次投递。

    2.如何解决重复

    主要是要求消息接收者来处理这种重复的情况,也就是要求消息接收者的消息处理是幂等操作。
    例如执行一条sql,update stat_table set count= 10 where id =1,即使执行n次,count值永远等于10.

    • 多版本并发控制,乐观锁的一种实现,在生产者发送消息时进行数据更新时需要带上数
      据的版本号,消费者去更新时需要去比较持有数据的版本号,版本号不一致的操作无法成功。 例如博客点赞次数自动+1 的接口:
      public boolean addCount(Long id, Long version);
      update blogTable set count= count+1,version=version+1 where id=321 and version=123
      每一个 version 只有一次执行成功的机会,一旦失败了生产者必须重新获取数据的最新 版本号再次发起更新。
    • 唯一性索引,保证某一类数据一旦执行完毕,后续同样的请求不再重复处理了(利用一张日志表来记录已经处理 成功的消息的 ID,如果新到的消息 ID 已经在日志表中,那么就不再处理这条消息。)

    3.描述下 RabbitMQ 概念里的 channel、exchange和 queue 这些概念及作用?

    • Queue 就是消息队列,用于存储消息,具有自己的 erlang 进程。
    • exchange 交换器,内部实现为保存 binding 关系的查找表;
    • channel 信道,是实际进行路由工作的实体,即负责按照 routing_key 将 message 投递给 queue 。在 RabbitMQ 中所有客户端与 RabbitMQ 之间的通讯都是在 channel 上,channel 是真实 TCP 连接之上的虚拟连接,所有 AMQP 命令都是通过 channel 发送的。

    4.RabbitMQ 中的元数据有哪些?

    元数据主要分为 Queue 元数据(queue 名字和属性等)、Exchange 元数据(exchange 名字、类型和属性等)、Binding 元数据(存放路由关系的查找表)、Vhost 元数据(vhost 范围内针对前三者的名字空间约束和安全属性设置),另外在集群中,元数据都是在一个 broker 中都是全局复制的。

    5.RabbitMQ中的vhost 是什么?起什么作用?

    vhost 可以理解为虚拟 broker ,即一个迷你版的 RabbitMQ server。其内部均含有独立 的 queue、exchange 和 binding 等,但最最重要的是,其拥有独立的权限系统,可以做到vhost 范围的用户控制。当然,从 RabbitMQ 的全局角度,vhost 可以作为不同权限隔离的手段(一个典型的例子就是不同的应用可以跑在不同的 vhost 中)。

    6.RabbitMQ 上的一个 queue 中存放的 message 是 否有数量限制?

    默认情况下一般是无限制,因为限制取决于机器的内存,但是消息过多会导致处理效率 的下降。同时可以通过参数来限制, x-max-length :对队列中消息的条数进行限制 , x-max-length-bytes :对队列中消息的总量进行限制。
    7.为什么对所有的 message 都使用持久化机制?

    • 首先,必然导致性能的下降,因为写磁盘比写内存慢的多,Rabbit 的吞吐量有 10 倍的差距。
    • 其次,message 的持久化机制用在 RabbitMQ 的集群时会出现“坑爹”问题。矛盾点 在于,要实现持久化的话,必须消息、消息队列、交换器三者持久化,如果集群中不同机器 中三者属性有差异,会发生不可预料的问题。
      所以一般处理原则是:仅对关键消息作持久化处理(根据业务重要程度),且应该保证关键消息的量不会导致性能瓶颈。

    7.RAM node 和 disk node 的区别?

    RAM node 就是内存节点,Rabbit 中的 queue、exchange 和 binding 等 RabbitMQ 基础构件中相关元数据保存到内存中,disk node 是磁盘节点,上述数据会在内存和磁盘中均进行存储。
    一般在 RabbitMQ 集群中至少存在一个 disk node.

    8.RabbitMQ 如何确保消息的可靠性传输?

    • 生产者
      生产者 那里设置开启 confirm 模式
      你每次写的消息都会分配一个唯一的 id,然后如果写入了 RabbitMQ 中,RabbitMQ 会给你回传一个 ack 消息,告诉你说这个消息 ok 了
      如果 RabbitMQ 没能处理这个消息,会回调你一个 nack 接口,告诉你这个消息接收失败,你可以重试。而且你可以结合这个机制自己在内存里维护每个消息 id 的状态,如果超过一定时间还没接收 到这个消息的回调,那么你可以重发。
    • 消费端
      消费端开启手动 ack 机制
      简单来说,就是你关闭 RabbitMQ 自动 ack, 可以通过一个 api 来调用就行,然后每次你自己代码里确保处理完的时候,再程序里 ack 一 把。这样的话,如果你还没处理完,不就没有 ack?那 RabbitMQ 就认为你还没处理完,这个时候 RabbitMQ 会把这个消费分配给别的 consumer 去处理,消息是不会丢的。

    相关文章

      网友评论

          本文标题:常见面试

          本文链接:https://www.haomeiwen.com/subject/iiidgctx.html