RabbitMQ的面试问题

RabbitMQ的面试问题

  1. 为什么使用消息队列啊?
  • [为什么在项目中要使用RabbitMQ呢?]
  • 这里涉及到了消息队列的功能,挑3个比较重要的功能讲
  • 1)解耦
    打个比方我们的服务A中会生产一个比较重要的数据,比如说用户信息的数据,这个数据会在服务B,服务C等等服务中去调用到,在我们使用MQ之前,我们的A服务需要根据其他服务的需求开发出相对应的接口去供其他服务调用用户信息数据,如果这时候不断用其他的服务需要调用,就要不断的去开发对应的接口,如果其他服务不需要了,又要将其删除,那么我们就说这个服务A耦合死了,那如何通过MQ打到解耦的效果呢?
    实际上,我们只需要针对服务A当做MQ的消息生产者,把用户信息发送到MQ中,这时候不管哪一个服务需要调用这个用户信息,只需要自己去监听服务A中设置的发送到MQ中的队列就可以了,从而打到了解耦的效果。
  • 2)异步
    那么如何体现出异步呢?打个比方来说,我们用户发送出了注册请求,我们的服务需要向数据库中写入用户注册的信息,并且还需要向其他的服务去写入数据,比如说用户注册日志服务等,那么这个写数据库的操作是需要花费时间的,这个时候我们用MQ让注册服务去发送用户信息到用户服务中心添加用户信息,我们注册日志服务就可以直接在注册服务中异步获取用户信息完成日志记录操作,从而打到了异步的效果,也就是说我们注册服务是100ms,注册日志服务需要300ms,这个时候通过异步,用户不会等待100+300ms了,从而打到用户的体验感的增强
  • 3)削峰
    打个比方在一个时间段用上万的请求涌入服务器,那么当这些请求同时访问MySQL数据库时,数据库会直接挂掉,导致整个系统挂掉,那么我们可以让这一万个请求先发送到MQ中,然后通过MQ的吞吐量的设置,每秒只发送2000请求到服务器中,从而避免了MySQL以及系统的崩溃
  1. 消息队列都有什么优点和缺点?
    有点有上面说的解耦,异步,削峰
    缺点呢?
    因为插入了MQ这个消息中间件,如果MQ消息中间件挂掉了,那么像上面说的解耦的情况,服务A的消息给BCDEF等服务器就发送不出去了,如果MQ没有挂掉BC都从A中获取了消息,修改了数据库的数据,但是D服务的监听出问题了,这个时候会产生消息的不一致,而且使用MQ的话会出现各种各样的问题,这些问题可能会导致整个项目的复杂性挺高n个档次,所以我们在使用之前会再三确定,确定业务逻辑确实需要时,再进行使用。

题外话:
目前4中常见的MQ
activeMQ :万级吞吐量,社区不活跃,逐渐被替代
RabbitMQ : 万级吞吐量,社区活跃
RocketMQ : 十万级吞吐量,阿里出品
kafka :十万级吞吐量,使用与大数据

  1. 如何保证消息队列的高可用啊?
    这里主要说道RabbitMQ的高可用,
    分为3钟
    1)单机模式
    单机模式就不多说了,主要是给我们进行测试使用
    2)集群模式
    集群模式,这里涉及到了一个元数据和消息数据的概念
    元数据:是指我们配置queue的一些初始化的数据
    我们集群了3个MQ,那么其中一个MQ的queue是有元数据和消息数据的,其他的两个上面只有元数据,当我们的服务监听到不带有消息数据的queue时,这个被监听的队列会找到有消息数据的MQ的queue中,然后通过后面queue给服务发送数据,这个集群方式非常麻烦,所以我们一般保证高可用时会使用镜像模式。
    3)镜像模式
    集群模式的优化版本,当我们使用了镜像模式时,消息发送者将消息发送到MQ的一个节点上时,其他说有的节点都会被同步这个消息,就像镜像一样每个节点上都有了这个消息的镜像,那么在消费时获得哪一个节点上的数据都是直接获得的了。
  2. 如何保证消息不被重复消费啊?如何保证消费的时候是幂等的啊?
    简单来说,当我们的生产者向RabbitMQ发送消息时,会给这个消息加上一个唯一的id,当我们的消费者从RabbitMQ中监听到了消息时这个id也会一起传递,那么我们有两种方法去防止重复消费的问题
    1)我们在消费者这边去用set集合来存储这个id,当消费者每次监听到消息时,都将监听到的id与set中的消息进行对比,如果没有相同的id,则将数据进行具体的业务操作,并且存储到set中
    2)我们可以利用数据库的主键来进行去重,当然这个得看具体的业务需求了。
  3. 如何保证消息的可靠性传输啊?要是消息丢失了怎么办啊?
    消息的丢失在整个过程中会有3个地方出现,
    ①当消息从生产者到消费者时,消息可能丢失,为了避免这种情况出现,我们可以首先在生产者发送消息之前,将这个消息提前存储到redis(或者其他的容器)中,我们要明白RabbitMQ中有两个机制,一个是事务机制,一个是confirm机制,第一个事务机制是同步的,消息生产者发送消息,如果MQ接受成功,则提交,不成功则回滚;confirm机制基于channel设置,如果队列和消息是持久化的,当消息被写入磁盘中是会发送确认信息给生产者,第一种效率太差,一般我们会设置confirm。
  4. 那如何保证消息的顺序性?
    为什么会出现顺序性的问题呢,因为我们的消息通过MQ发送给了不同的服务,不同的服务在处理这些消息时,不能保证其按照顺序去执行,解决方法,我们可以将所有的消息按照顺序放在同一个队列中就可以了。
  5. 如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?在这里插入图片描述
    1)先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都停掉
    2)新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量
    3)然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue
    4)接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据
    5)这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据
    6)等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息

(2)这里我们假设再来第二个坑

假设你用的是rabbitmq,rabbitmq是可以设置过期时间的,就是TTL,如果消息在queue中积压超过一定的时间就会被rabbitmq给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在mq里,而是大量的数据会直接搞丢。

这个情况下,就不是说要增加consumer消费积压的消息,因为实际上没啥积压,而是丢了大量的消息。我们可以采取一个方案,就是批量重导,这个我们之前线上也有类似的场景干过。就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比如大家一起喝咖啡熬夜到晚上12点以后,用户都睡觉了。

这个时候我们就开始写程序,将丢失的那批数据,写个临时程序,一点一点的查出来,然后重新灌入mq里面去,把白天丢的数据给他补回来。也只能是这样了。

假设1万个订单积压在mq里面,没有处理,其中1000个订单都丢了,你只能手动写程序把那1000个订单给查出来,手动发到mq里去再补一次

(3)然后我们再来假设第三个坑

如果走的方式是消息积压在mq里,那么如果你很长时间都没处理掉,此时导致mq都快写满了,咋办?这个还有别的办法吗?没有,谁让你第一个方案执行的太慢了,你临时写程序,接入数据来消费,消费一个丢弃一个,都不要了,快速消费掉所有的消息。然后走第二个方案,到了晚上再补数据吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值