0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MQ怎么保障消息可靠性?

数据分析与开发 来源:数据分析与开发 作者:数据分析与开发 2022-04-06 15:10 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

面试官:在MQ的整个消息生产消费过程中,如何保障消息100%被消费?

候选人:MQ有个ACK机制,确保消息100%被消费。

面试官:好吧,可以回去等通知了……

这道面试题在考察MQ组件时算是老生常谈了,不知道你是如何回答的?

我们平时都在使用MQ,但使用技术框架只是第一步,去弄明白它的底层原理、深挖技术真相,才是每一位IT从业者的基操。

这里说明一点,想要回答好面试官的问题,最好还是要有金字塔思维——金字塔思维就是从不同维度上来思考问题的一种方式,不重不漏,集体穷尽。

MQ作为异步通讯的消息中间件,其功能除了解耦生产者与消费者,还能用于大流量的削峰填谷,解决业务的最终一致性问题,那么消息的“可靠性”就显得尤为重要了,比如说商品出库后的库存数据通过MQ同步到财务系统,如果消息的可靠性没有保障,那财务系统的存货成本分析数据就无法有效支撑财务团队。

准确来说,我们需要保障MQ消息的可靠性,需要从三个层面/维度解决:生产者100%投递、MQ持久化、消费者100%消费,这里的100%消费指的是消息不少消费,也不多消费。

4856e7b8-ac99-11ec-aa7f-dac502259ad0.png

由于MQ是基础网络通讯的中间件,网络通讯必然因丢包、网络抖动等原因产生数据丢失,MQ组件本身也会由于宕机或软件崩溃而中止服务,从而造成数据丢失,那么我们就需要从这两个根本原因着手补偿,这里科普一下RabbitMQ和Kafka是怎么解决的。

RabbitMQ

这里我必须先提一提RabbitMQ的消息协议——AMQP(Advanced Message Queuing Protocol,高级消息队列协议),在面试时我经常问候选人一个问题:RabbitMQ用的是什么消息协议?大部分候选人是回答不出来AMQP的,更不用说AMQP模型是如何设计的了。 在服务器中,三个主要功能模块连接成一个处理链完成预期的功能:

486b621a-ac99-11ec-aa7f-dac502259ad0.png

Exchange:接收发布应用程序发送的消息,并根据一定的规则将这些消息路由到消息队列

Queue:存储消息,直到这些消息被消费者安全处理完为止

Binding:定义了exchange和queue之间的关联,提供路由规则

使用这个模型我们可以很容易地模拟出存储转发队列和主题订阅这些典型的消息中间件概念。 接下来我们看看RabbitMQ的消息确认机制是如何保障消息可靠性的。一、生产者端

通过API将信道(channel)设置为confirm模式,则每条消息会被分配一个唯—ID

如果消息投递成功,也就是说消息已经到达broker了,信道会发送ack给生产者,回调ConfirmCallback接口,带上唯一ID

如果发生错误导致消息丢失,比如通过某个RoutingKey无法路由到某个Queue,则会发送nack给生产者,回调ReturnCallback接口,并带上唯一ID和异常信息

ack和nack只有一个被触发,只触发一次,而且是异步执行,意味着生产者不需要等待,可以继续发送新消息

二、消费者端

声明队列时,指定noack=false, 表示消费者不会自动提交ack,broker会等待消费者手动返回ack、才会删除消息,否则立刻删除

broker的ack没有超时机制,只会判断链接是否断开,如果断开了(比如消费者处理消息过程中宕机),消息会被重新发送,所以消费者要做好消息幂等性处理

此外,RabbitMQ除了消息确认机制,还有另一种方式——使用事务消息:消息生产端发送commit命令,MQ同步返回commit ok命令,这种方式由于需要同步阻塞等待MQ返回是否投递成功,才能执行别的操作,性能较差,因此不推荐使用。三、MQ本身通常来说,消息是在内存中存储通讯的,而基于内存的都是会有数据丢失的问题产生,服务一重启,数据就随之销毁。 在RabbitMQ中对数据的持久化有三方面:交换机持久化、队列持久化、消息持久化。

交换机持久化:exchange_declare创建交换机时通过参数durable=true指定,如:channel.exchangeDeclare(exchangeName, “direct/topic/header/fanout”,true);第三个参数就是设置durable值

队列持久化:queue_declare创建队列时通过参数durable=true指定,如:channel.queueDeclare("queue.persistent.name",true, false, false, null),第二个参数就是设置durable值

消息持久化:new AMPQMessage创建消息时通过参数指定,如:channel.basicPublish("exchange.persistent", "persistent",MessageProperties.PERSISTENT_TEXT_PLAIN, "persistent_test_message".getBytes()),或者设置参数deliveryMode=2来指定:AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();builder.deliveryMode(2);

上面只是说了API层的实现,那RabbitMQ底层又是怎么做消息持久化的呢?如果指定了持久化参数,它们会以append的方式写文件,会根据文件大小(默认16M)自动切割,生成新的文件,RabbitMQ启动时会创建两个进程,一个负责持久化消息的存储,另一个负责非持久化消息的存储(当内存不够时会用到)。 消息存储时,会在一个叫ets的表中记录消息在文件中的映射以及相关信息(包括ID、偏移量、有效数据、左边文件、右边文件),消息读取时根据该信息到文件中读取,同时更新信息。 消息删除时只从ets删除,变为垃圾数据,当垃圾数据超出比例(默认50%),并且文件数达到3个,就会触发垃圾回收:锁定左右两个文件,整理左边文件有效数据、将左边文件有效数据写入左边,更新文件信息,删除右边,完成合并;当一个文件的有效数据等于0时,删除该文件。 写入文件前先写入buffer缓冲区,如果buffer已满,则写入文件,注意,此时只是操作系统的页存,还没落盘。 每隔25ms刷一次磁盘(比如Linux中的fsync命令),不管buffer(fd的读、写缓存区)满没满,都将buffer和页存中的数据落盘。 还有另外一种落盘机制:每次消息写入后,如果没有后续写入请求,则直接刷盘。 KafkaKafka在MQ领域以性能高、吞吐能力强、消息堆积能力强等等优势称著,常常用于日志收集、消息系统、用户活动跟踪、运营指标、流式处理等等场景,讲之前先简单聊聊Kafka的架构设计:

48864116-ac99-11ec-aa7f-dac502259ad0.jpg

Consumer Group:消费者组,消费者组内每个消费者负责消费不同分区的数据,提高消费能力,这是逻辑上的一个订阅者。

Topic:可以理解为一个队列,Topic将消息分类,生产者和消费者面向的是同一个Topic。

Partition:为了实现扩展性,提高并发能力,一个Topic以多个Partition的方式分布到多个Broker上,每个Partition是一个有序的队列,一个Topic的每个Partition都有若干个副本(Replica),一个Leader和若干个Follower;生产者发送数据的对象,以及消费者消费数据的对象,都是通过Leader,Follower负责实时从Leader中同步数据,保持和Leader数据的同步;当Leader发生故障时,某个Follower还会成为新的Leader。

一、生产者端Kafka消息发送端有个ACK机制。

设置ack参数:ack=0,表示不重试,Kafka不需要返回ack,极有可能各种原因造成丢失;ack=1,表示Leader写入成功就返回ack了,Follower不一定同步成功;ack=all或ack=-1,表示ISR列表中的所有Follower同步完成再返回ack。

设置参数unclean.leader.election.enable: false,禁止选举ISR以外的Follower为Leader,只能从ISR列表中的节点中选举Leader;可能会牺牲Kafka的可用性,但是能够提高消息的可靠性。

重试机制,设置tries > 1,表示消息重发次数。

设置最小同步副本数min.insync.replicas > 1,没满足该值前,Kafka不提供读写服务,写操作会异常。

通过设置最小同步副本数和ACK机制,可以让MQ在性能与可靠性上达到平衡。二、消费者端手工提交offset(偏移量):Kafka消费者在拉取消息后,默认会自动提交offset,由于消费者每次都会根据offset来消费消息的,如果消费者处理业务失败,实际上我们是要重新消费的,所以我们要在消息处理成功后再手工提交offset,确认消息能够成功消费。 同样地,消费者的业务代码也要做好幂等性校验。三、MQ本身很简单,通过减小broker刷盘间隔来实现高可靠。 要深究其原理,得从Kafka的持久化机制来看。

磁盘的顺序读写:与RabbitMQ不同,Kafka是基于磁盘读写的,那为什么Kafka的吞吐量还这么大呢?原因是Kafka的读写是用顺序读写的,不需要寻址随机读写,而由于是用磁盘来写数据,消息堆积能力必然比内存型的RabbitMQ更强

利用了操作系统的零拷贝技术:避免CPU将数据从一块存储拷贝到另外一块存储,关于零拷贝这里不详述,与Java应用不同,Kafka的消息不需要在用户缓冲区处理磁盘数据再返回,所以才能用零拷贝技术

分区分段+索引:Kafka的消息实际上分布存储在一个一个小的segment中的,每次文件读写也是直接操作segment,为了进一步优化查询,Kafka又默认为分段后的数据文件建立了索引文件(就是文件系统上的.index文件),这种分区分段+索引的设计,不仅提升了数据读取的效率,同时也提高了数据操作的并行度(类似ConcurrentHashMap的分段锁机制)。

批量压缩&批量读写:多条消息一起压缩进行传输(比如gzip格式)与读写,节省带宽

直接操作page cache:虽然Kafka是Java写的,也基于JVM运行,但Kafka的消息读写是直接操作操作系统页存的,而不是在JVM的堆内存,这样就避免JVM的GC耗时及对象创建耗时,且读写速度更高,JVM进程重启缓存也不会丢失

理解了Kafka的持久化机制是直接读写页存+定时刷盘的方式,我们只需要设置刷盘策略即可在性能与可靠性上权衡。 Kafka提供3个参数来优化刷盘机制:

log.flush.interval.messages //多少条消息刷盘1次

log.flush.interval.ms //隔多长时间刷盘1次

log.flush.scheduler.interval.ms //周期性的刷盘。

总结一下关于框架类的面试题,最重要是得掌握技术框架的底层实现原理、适用场景,基本上回答出这两方面就OK了,其它奇奇怪怪的细节问题要是答不出来,咱就引导面试官说出自己对框架的理解即可,毕竟细节的问题太多了。那怎么才算掌握呢?起码能通过框架的特性,根据需要实现一个简易版本,比如说自己实现一个Spring框架、实现一个MQ组件等等。

由浅入深,化难为易。

审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 模型
    +关注

    关注

    1

    文章

    3649

    浏览量

    51719
  • 消息
    +关注

    关注

    0

    文章

    29

    浏览量

    13026
  • 网络通讯
    +关注

    关注

    0

    文章

    78

    浏览量

    12599

原文标题:面试基操:MQ 怎么保障消息可靠性?

文章出处:【微信号:DBDevs,微信公众号:数据分析与开发】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    可靠性设计的十个重点

    保障。规定定性定量的可靠性要求规定定性定量的可靠性要求。有了可靠性指标,开展可靠性设计才有目标,才能对开发的产品
    的头像 发表于 08-01 22:55 795次阅读
    <b class='flag-5'>可靠性</b>设计的十个重点

    太诱MLCC电容的可靠性如何?

    众所周知,多层陶瓷电容器(MLCC)已成为消费电子、汽车电子、工业控制等领域的核心被动元件。太阳诱电(太诱)通过材料创新、工艺优化与严苛测试体系,构建了MLCC电容的可靠性护城河,其产品失效率长期
    的头像 发表于 07-09 15:35 509次阅读

    关于LED灯具的9种可靠性测试方案

    LED灯具的可靠性试验,与传统灯具有显著区别。作为新一代光源,LED灯具正在逐渐取代传统节能灯的市场,因此无法简单地沿用传统灯具的测试方法。那么,LED灯具需要进行哪些可靠性试验呢?标准名称:LED
    的头像 发表于 06-18 14:48 685次阅读
    关于LED灯具的9种<b class='flag-5'>可靠性</b>测试方案

    可靠性测试包括哪些测试和设备?

    在当今竞争激烈的市场环境中,产品质量的可靠性成为了企业立足的根本。无论是电子产品、汽车零部件,还是智能家居设备,都需要经过严格的可靠性测试,以确保在各种复杂环境下都能稳定运行,为用户提供可靠的使用体验。那么,
    的头像 发表于 06-03 10:52 1118次阅读
    <b class='flag-5'>可靠性</b>测试包括哪些测试和设备?

    半导体测试可靠性测试设备

    在半导体产业中,可靠性测试设备如同产品质量的 “守门员”,通过模拟各类严苛环境,对半导体器件的长期稳定性和可靠性进行评估,确保其在实际使用中能稳定运行。以下为你详细介绍常见的半导体测试可靠性测试设备。
    的头像 发表于 05-15 09:43 912次阅读
    半导体测试<b class='flag-5'>可靠性</b>测试设备

    电子元器件可靠性检测项目有哪些?

    沉淀和丰富的实践经验,在其专业团队看来,严格且全面的可靠性检测项目是保障电子元器件质量的核心所在。那么,究竟有哪些检测项目能让电子元器件在复杂环境中稳定运行、可靠
    的头像 发表于 05-14 11:44 658次阅读
    电子元器件<b class='flag-5'>可靠性</b>检测项目有哪些?

    提供半导体工艺可靠性测试-WLR晶圆可靠性测试

    随着半导体工艺复杂度提升,可靠性要求与测试成本及时间之间的矛盾日益凸显。晶圆级可靠性(Wafer Level Reliability, WLR)技术通过直接在未封装晶圆上施加加速应力,实现快速
    发表于 05-07 20:34

    电机微机控制系统可靠性分析

    可靠性是电机微机控制系统的重要指标,延长电机平均故障间隔时间(MTBF),缩短平均修复时间(MTTR)是可靠性研究的目标。电机微机控制系统的故障分为硬件故障和软件故障,分析故障的性质和产生原因,有
    发表于 04-29 16:14

    IGBT的应用可靠性与失效分析

    包括器件固有可靠性和使用可靠性。固有可靠性问题包括安全工作区、闩锁效应、雪崩耐量、短路能力及功耗等,使用可靠性问题包括并联均流、软关断、电磁干扰及散热等。
    的头像 发表于 04-25 09:38 2307次阅读
    IGBT的应用<b class='flag-5'>可靠性</b>与失效分析

    保障汽车安全:PCBA可靠性提升的关键要素

    汽车电子PCBA的可靠性提升要点 随着汽车智能化、网联化的快速发展,汽车电子在整车中的占比不断提升,其重要日益凸显。作为汽车电子的核心部件,PCBA(印制电路板组装)的可靠性直接关系到汽车的安全
    的头像 发表于 04-14 17:45 511次阅读

    电路可靠性设计与工程计算技能概述

    电路可靠性设计与工程计算通过系统学习电路可靠性设计与工程计算,工程师不仅能提高电路的可靠性和稳定性,还能优化产品设计过程,减少潜在的故障风险,从而提升产品的市场竞争力和消费者信任度。为什么工程师需要
    的头像 发表于 03-26 17:08 617次阅读
    电路<b class='flag-5'>可靠性</b>设计与工程计算技能概述

    半导体集成电路的可靠性评价

    半导体集成电路的可靠性评价是一个综合的过程,涉及多个关键技术和层面,本文分述如下:可靠性评价技术概述、可靠性评价的技术特点、可靠性评价的测
    的头像 发表于 03-04 09:17 1269次阅读
    半导体集成电路的<b class='flag-5'>可靠性</b>评价

    一文读懂芯片可靠性试验项目

    可靠性试验的定义与重要可靠性试验是一种系统化的测试流程,通过模拟芯片在实际应用中可能遇到的各种环境条件和工作状态,对芯片的性能、稳定性和寿命进行全面评估。在芯片研发和生产过程中,可靠性
    的头像 发表于 02-21 14:50 1857次阅读
    一文读懂芯片<b class='flag-5'>可靠性</b>试验项目

    汽车车灯检测与可靠性验证

    。因此,对汽车车灯进行严格的检测和可靠性验证是保障车灯质量的必要环节。汽车车灯检测的范围1.前部车灯前部车灯是车辆照明系统的重要组成部分,包括前雾灯、前照灯、前转
    的头像 发表于 02-17 17:24 829次阅读
    汽车车灯检测与<b class='flag-5'>可靠性</b>验证

    霍尔元件的可靠性测试步骤

    霍尔元件是一种利用霍尔效应来测量磁场的传感器,广泛应用于电机控制、位置检测、速度测量以及电流监测、变频控制测试、交直流电源、电源逆变器和电子开关等领域。为了确保霍尔元件的性能和可靠性,进行全面
    的头像 发表于 02-11 15:41 1200次阅读