美文网首页
消息队列面试题

消息队列面试题

作者: 华木公子 | 来源:发表于2019-07-25 20:53 被阅读0次

    一. 为什么要使用消息队列

    • 消息队列可以对系统进行解耦,提高响应速度,系统功能向内聚合,对外开放;
    • 消息队列可以对系统异步功能进行剥离,减少功能耦合,提供开发效率;
    • 消息队列可以削峰限流,确保下游消费者稳定运行;

    二. 消息队列有什么缺点

    • 系统可靠性降低,解耦后,多个系统通过消息中间件交互,消息中间件挂了整个系统就挂了;
    • 系统开发复杂度提升,需要考虑消息的处理,包括消息幂等性(重复消费问题),消息保序性(一个订单多条消息问题),以及消息中间件本身的持久化和稳定性可靠性;
    • 消息一致性问题,如果一个功能发给多个系统,要所有系统都执行成功才算成功时,需要确保一个功能多个消息的完整一致性;

    三. 各种MQ的比较

    特性 activeMQ rabbitMQ rocketMQ kafka
    单机吞吐量 万/秒 万/秒 10万/秒 10万/秒
    topic对吞吐量的影响 topic达到几百/几千个级别,吞吐量会有小幅下降;
    这是rocket的最大优势
    所以非常适用于支撑大批量topic场景
    topic可以达到几十/几百个级别,吞吐量会有大幅下降
    kafka不适用大批量topic场景,除非加机器
    时效性 毫秒 微秒
    这是rabbit 最大优势,延迟低
    毫秒 毫秒
    可用性 高。主从架构 高。主从架构 非常高。分布式。 非常高。分布式。数据多副本,不会丢数据,不会不可用。
    可靠性 有较低概率丢失数据 ---- 经配置优化可达到0丢失 经配置优化可达到0丢失
    功能特性 功能齐全,但已不怎么维护 erlang开发,并发强,性能极好,延迟低 MQ功能较为齐全,扩展好 功能简单,主要用于大数据实时计算和日志采集,事实标准

    综上,总结如下:


    【activeMQ】

    • 优点:技术成熟,功能齐全,历史悠久,有大量公司在使用
    • 缺点:偶尔会有较低概率丢失数据,而且社区已经不怎么维护5.15.X版本
    • 使用场景:主要用于系统解耦和异步处理,不适用与大数据量吞吐情况。互联网公司很少适用

    【rabitMQ】

    • 优点:吞吐量高,功能齐全,管理界面易用,社区活跃,性能极好,;
    • 缺点:吞吐量只是万级,erlang难以二次开发和掌控;集群动态扩展非常麻烦;
    • 使用场景:吞吐量不高而要求低延迟,并且不会频繁调整和扩展的场景。非常适合国内中小型互联网公司适用,因为管理界面非常友好,可以在界面进行配置和优化/集群监控。

    【rocketMQ】

    • 优点:支持百千级大规模topic。吞吐量高(十万级,日处理上百亿)。接口易用。,分布式易扩展,阿里支持。java开发易于掌控。
    • 缺点:与阿里(社区)存在绑定。不兼容JMS规范。
    • 使用场景:高吞吐量

    【kafka】

    • 优点:超高吞吐量,超高可用性和可靠性,分布式易扩展
    • 缺点:topic支持少,MQ功能简单,消息可能会重复消费影响数据精确度
    • 使用场景:超高吞吐量场景而数据精确度没那么高,天然适合大数据实时计算和日志采集场景

    三. activeMQ和rabbitMQ/kafka的架构图

    四. 消息如何保证幂等性

    例如kafka的offset可能是消费者批量处理后才提交到zk,重启后再消费时就可能会收到重复消息,需要消费者在处理消息时做幂等性设计,即先判断是否消费过,把已消费的放到本地缓存或者redis中,每次消费时先做个判断即可。

    五 消息如何保证不丢失

    生产者投递消息到MQ,MQ存储消息,消费者从MQ消费消息:
    要分别确保上述三个过程都是成功的,有如下做法:


    【以rabbitMQ举例】

    • 对于生产消息阶段:
    1. 发送时启用消息事务,channel发送失败就回滚。但是不推荐使用,因为事务时同步的,性能会下降。
    2. 发送时使用confirm模式(就是回调模式)。推荐使用,因为是异步的,吞吐量高。消息发送后,回调消息发送成功或者失败的接口。那么业务层面也就可以根据是否发送成功和失败做处理,比如发送前缓存到redis,发送成功后从redis中移除,对于在redis中一直没有处理的,再进行重发操作。
    • MQ存储消息:
    1. 对queue进行持久化
    2. 对queue的数据进行持久化
    • 消费者从MQ消费消息

    一般出现在autoACK模式下,即收到消息就反馈给MQ已处理,但消费者本身还没有真正完成处理就挂了,那么这个消息就会丢失(重启后也找不到了)。
    解决方案:业务逻辑处理完后再手动对消息进行ACK。

    capture_20190729145426349.jpg

    【以kafka举例】

    • MQ持久化本身丢数据

    主要是因为kafka的多分区机制,当数据从leader的partition同步到其他follower的partition时,刚好leader挂了,此时选举某个同步慢的follower为leader,此时未同步的数据就丢失。需要从如下三个方面进行配置:

    1. 每个topic的partition副本应该大于1;以确保数据有备份;
    2. leader能够感知到至少有一个follower与自己是快速同步不掉队的;以确保切换leader是可行的;
    3. 数据在所有follower的partition中存储完成后,才给生成者发送ack消息;以确保所有partition的消息保持一致;
    4. 生产者可设置发送失败后无限重试(也就会卡住,消息不会丢);
    • 消费者丢数据

    与上述rabbit情况相同,主要是autoACK模式造成offset自动提交,建议都做成手动提交offset。

    六 如何保证消息顺序

    • 对于activeMQ,可以通过exclusive方式让一个queue始终被一个consumer消费;或者messageGroup方式;
    • 对于rabitMQ, 一个queue对应一个consumer才行,多个consumer对应一个queue就容易错乱;
    • 对于kafka,partition的消息是保序的。然后它强制要求一个partition只能投递给同组内的一个consume(即partition出只能有一个consumer,不能投递给同组内两个consumer,只是同组内的consumer却可以消费多个partition),所以不存在多个消费者错乱的问题。然后生产者可以设定一个key,同一个key的可以发送到同一个partition中,这样同一个key的消息在partition中是保序;
    • 如果kafka在消费端开启多线程,也会出现乱序。可以在消费端加队列,按照业务保序增加内存队列,这样队列中的消息与partition中顺序是一致的,然后多线程从队列中取数据,每次取一个完整顺序的消息进行处理即可。如下图:


      capture_20190729145426349.jpg

    七 消息队列积压怎么办

    • 当消费者出现异常,很容易引起队列积压,如果一秒钟1000个消息,那么一个小时就是几千万的消息积压,是非常可怕的事情,但是生产线上又有可能会出现;
    • 当消息积压来不及处理,rabbitMQ如果设置了消息过期时间,那么就有可能由于积压无法及时处理而过期,这消息就被丢失了;

    解决方法如下:

    • 不建议在生产环境使用数据过期策略,一是数据是否丢失无法控制,二是一旦积压就很有可能丢失;建议数据的处理都有代码来控制;
    • 当出现消息积压时,做法就是临时扩大consumer个数,让消息快速消费,一般都是通过业务逻辑的手段来完成:如下:

    【rabbitmq解决积压范例】

    1. 修复consumer代码故障,确保consumer逻辑正确可以消费;
    2. 停止consumer,开启10倍20倍的queue个数;
      * 创建一个临时的consumer程序,消费积压的queue,并把消息写入到扩建的10倍queue中;
      * 再开启10倍20倍的consumer对新的扩充后队列进行消费;
      * 这种做法相当于通过物理资源扩充了10倍来快速消费;
    1. 当消费完成后,需要恢复原有架构,开启原来的consumer进行正常消费;

    【kafka解决范例】

    1. 修复consumer代码故障,确保consumer逻辑正确可以消费;
    2. 停止consumer,新建topic,新建10倍20倍的partition个数;
      * 创建对应原topic的partition个数的临时的consumer程序,消费原来的topic,并把消息写入到扩建的新topic中;
      * 再开启对应新partition个数的consumer对新的topic进行消费;
      * 这种做法相当于通过物理资源扩充了10倍来快速消费;
    1. 当消费完成后,需要恢复原有架构,开启原来的consumer进行正常消费;

    相关文章

      网友评论

          本文标题:消息队列面试题

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