面试中消息队列的问题

消息队列的匹配规则

1.消息队列模式
消息队列模式:发送者,接受者

2.主题消息模式
主题消息:发布者,订阅者

3.Rabbitmq消息确认机制
通过持久化数据的方式,生产者将消息发送出去之后,消息到底有没有达到rabbitmq服务器默认是不知道的。

消息队列如何确保其消息的顺序性

通常来说有以下的思路

  • 单线程消费来确保消息的顺序性
  • 对消息进行编号,消费者处理时根据编号判断顺序。

rabbitmq:(队列消息的思路)
拆分多个queue,每个queue一个consumer。或者就一个queue但是对应一个consumer,然后这个consumer内部用内存队列做排队,然后分发给底部不同worker处理

  • 防止使用同一个队列,导致数据123进入不同的消费者,从而使得数据123没有按指定的顺序被执行

  • 通过拆分queue来保证每一个消费者都能获得完整的数据123,然后消费者内部进行排队,从而保证消息的有序性。

  • 这里同时也要设计,保证消息的幂等性。
    在这里插入图片描述
    kafka
    一个topic,一个partition(分割),一个consumer,内部单线程消费,写N个内存queue,然后N个线程分别消费一个内存queue。

  • 通过指定key的方式,来确保相关的数据123会分发到同一个partition

  • partition会内部对其进行排序,保证其有序性。
    在这里插入图片描述

消息队列如何保证其不会重复消费

简单来说,如何实现消息的幂等性,即消息执行一次和执行多次的结果是一样的。
保证数据不会重复消费,要结合业务来实现

  1. 比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 一下好吧。
  2. 比如你是写 Redis,那没问题了,反正每次都是 set,天然幂等性。
  3. 比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id
    之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个
    id 写 Redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。
  4. 比如基于数据库的唯一键来保证重复数据不会重复插入多条。因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。

消息队列如何保证消息不会丢失

消息从生产到消费可以经历三个阶段:生产阶段、存储阶段和消费阶段。
生产阶段:在这个阶段,从消息在生产者创建出来,经过网络传输到消息队列服务器中。
存储阶段:消息在消息队列服务器中存储,如果是集群,消息会在这个阶段被复制到其他的副本上。
消费阶段:消费者从消息队列服务器中拉取消息,通过网络传输发送到消费者。
而解决消息队列在整个过程中不会消息丢失的方式,就是借助消息队列的应答模式来实现。

应答模式
消费者完成消费处理后,会发送一个消费应答,告诉消息队列服务器这个消息已经处理完成可以删除这个消息了,如果一个消费者由于宕机
没有发送消息应答,那么消息队列服务器会认为消息发送失败,自动进行补偿行为,即将这个消息重新加入队列,重新投递。
应答模式又分为自动应答和手动应答,区别在于告诉消息队列服务删除消息的时间点是否要手动删除。
应答模式牺牲了消息队列的性能,从而提高了消息的可靠性。

消息队列如何解决消息堆积问题

消息队列除了有异步解耦的功能,还有挡住前端数据洪峰的功能。

  1. 修复现有consumer的问题,并将其停掉。
  2. 重新创建一个容量更大的topic,比如patition是原来的10倍。
  3. 编写一个临时consumer程序,消费原来积压的队列。该consumer不做任何耗时的操作,将消息均匀写入新创建的队列里。
  4. 将修复好的consumer部署到原来10倍的机器上消费新队列。
  5. 消息积压解决后,恢复原有架构

核心思路,提高消费者的消费能力。

在RabbitMQ提供了一个消息回推机制可以解决消息堆积的问题
在RabbitMQ2.0之前
如果发布者应用程序因为发布消息太快而开始对RabbitMQ造成压力,那么RabbitMQ将发送Channel.FlowRPC方法来让你的发布者阻塞,即发布者不能发送任何消息直到收到另一条Channel.Flow命令为止。
但是,存在发布者没有监听Channel.Flow方法的极端情况。

在RabbitMQ3.2之后
采用TCP背压的机制来解决这种极端情况,采用一个连接信用阈值的机制,RabbitMQ将根据RPC请求的完成情况给每一个发布者打分,RabbitMQ只处理有足够信用的发布者的消息。
同时借助Connection.Blocked和Connection.Unblocked这两个异步方法,来通知客户端进行阻塞和取消阻塞。

发布了226 篇原创文章 · 获赞 40 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_40990818/article/details/104247085