面试官:如何保证RocketMQRabbitMQ消息数据100%不丢失

面试官:如何保证RocketMQRabbitMQ消息数据100%不丢失,第1张

在分布式系统的网络中,保证消息的可靠性?阿里技术分享了一篇文章:RocketMQ如何保证消息的可靠性?在文中详情介绍了RocketMQ是如何最大限度的保证消息不丢失的呢?分析的思路就是一条消息从产生到最终消费的整个过程,在三个关键的阶段去控制消息的可靠性。

下面分享证RabbitMQ如何保证消息的可靠性,对比去看,一定会有收获~

正在学RabbitMQ,特此记录一下,这里就不讲RabbitMQ基础了,直接进入主题。我们都知道,消息从生产端到消费端消费要经过3个步骤:

这3个步骤中的每一步都有可能导致消息丢失,消息丢失不可怕,可怕的是丢失了我们还不知道,所以要有一些措施来保证系统的可靠性。这里的可靠并不是一定就100%不丢失了,磁盘损坏,机房爆炸等等都能导致数据丢失,当然这种都是极小概率发生,能做到99999999%消息不丢失,就是可靠的了。下面来具体分析一下问题以及解决方案。

生产端可靠性投递,即生产端要确保将消息正确投递到RabbitMQ中。生产端投递的消息丢失的原因有很多,比如消息在网络传输的过程中发生网络故障消息丢失,或者消息投递到RabbitMQ时RabbitMQ挂了,那消息也可能丢失,而我们根本不知道发生了什么。针对以上情况,RabbitMQ本身提供了一些机制。

事务消息机制由于会严重降低性能,所以一般不采用这种方法,我就不介绍了,而采用另一种轻量级的解决方案——confirm消息确认机制。

什么是confirm消息确认机制?顾名思义,就是生产端投递的消息一旦投递到RabbitMQ后,RabbitMQ就会发送一个确认消息给生产端,让生产端知道我已经收到消息了,否则这条消息就可能已经丢失了,需要生产端重新发送消息了。

通过下面这句代码来开启确认模式:

然后异步监听确认和未确认的消息:

这样就可以让生产端感知到消息是否投递到RabbitMQ中了,当然这样还不够,稍后我会说一下极端情况。

那消息持久化呢?我们知道,RabbitMQ收到消息后将这个消息暂时存在了内存中,那这就会有个问题,如果RabbitMQ挂了,那重启后数据就丢失了,所以相关的数据应该持久化到硬盘中,这样就算RabbitMQ重启后也可以到硬盘中取数据恢复。那如何持久化呢?

message消息到达RabbitMQ后先是到exchange交换机中,然后路由给queue队列,最后发送给消费端。

所有需要给exchange、queue和message都进行持久化:

exchange持久化:

queue持久化:

message持久化:

这样,如果RabbitMQ收到消息后挂了,重启后会自行恢复消息。

到此,RabbitMQ提供的几种机制都介绍完了,但这样还不足以保证消息可靠性投递RabbitMQ中,上面我也提到了会有极端情况,比如RabbitMQ收到消息还没来得及将消息持久化到硬盘时,RabbitMQ挂了,这样消息还是丢失了,或者RabbitMQ在发送确认消息给生产端的过程中,由于网络故障而导致生产端没有收到确认消息,这样生产端就不知道RabbitMQ到底有没有收到消息,就不好做接下来的处理。

所以除了RabbitMQ提供的一些机制外,我们自己也要做一些消息补偿机制,以应对一些极端情况。接下来我就介绍其中的一种解决方案——消息入库。

消息入库 消息入库,顾名思义就是将要发送的消息保存到数据库中。

首先发送消息前先将消息保存到数据库中,有一个状态字段status=0,表示生产端将消息发送给了RabbitMQ但还没收到确认;在生产端收到确认后将status设为1,表示RabbitMQ已收到消息。这里有可能会出现上面说的两种情况,所以生产端这边开一个定时器,定时检索消息表,将status=0并且超过固定时间后(可能消息刚发出去还没来得及确认这边定时器刚好检索到这条status=0的消息,所以给个时间)还没收到确认的消息取出重发(第二种情况下这里会造成消息重复,消费者端要做幂等性),可能重发还会失败,所以可以做一个最大重发次数,超过就做另外的处理。

这样消息就可以可靠性投递到RabbitMQ中了,而生产端也可以感知到了。

既然已经可以让生产端100%可靠性投递到RabbitMQ了,那接下来就改看看消费端的了,如何让消费端不丢失消息。

默认情况下,以下3种情况会导致消息丢失:

其实,上述3中情况导致消息丢失归根结底是因为RabbitMQ的自动ack机制,即默认RabbitMQ在消息发出后就立即将这条消息删除,而不管消费端是否接收到,是否处理完,导致消费端消息丢失时RabbitMQ自己又没有这条消息了。

所以就需要将自动ack机制改为手动ack机制。

消费端手动确认消息:

这样,当autoAck参数置为false,对于RabbitMQ服务端而言,队列中的消息分成了两个部分:一部分是等待投递给消费端的消息;一部分是已经投递给消费端,但是还没有收到消费端确认信号的消息。如果RabbitMQ一直没有收到消费端的确认信号,并且消费此消息的消费端已经断开连接或宕机(RabbitMQ会自己感知到),则RabbitMQ会安排该消息重新进入队列(放在队列头部),等待投递给下一个消费者,当然也有能还是原来的那个消费端,当然消费端也需要确保幂等性。

好了,到此从生产端到RabbitMQ再到消费端的全链路,就可以保证数据的不丢失。

由于个人水平有限,有些地方可能理解错了或理解不到位的,请大家多多指出!Thanks

以上 RabbitMQ 原文链接 :htts://blogcsdnnet/hsz2568952354/article/details/86559470

最后分享一个梳理的消息中间件的思维导图,和面试题。

如需高清思维导图和面试题,关注私信获取。

if我是一名前端Dev,在我项目的技术栈中有这样一个工具:RabbitMQ。

当我们寻找技术资料的时候,几乎都是先讲RabbitMQ的内部概念,再附加上几个应用场景。

我明白这样介绍的目的是为了我们能够理解,但是事与愿违,实际上要经过上面的过程,你会发现很难起到明显的作用,仍旧不知道什么时候用,怎么用。原因主要有两个吧:

1,不像前端开发工具那样,和另外一个工具比较着就能逐渐学会;

2,涉及不到使用MQ的场景;

所以我用和MQ类似的前端技术来讲,看看是不是能够讲MQ讲明白。

一旦遇到RabbitMQ,我们只需要将焦点MQ(Message Queue)这两个字母上,因为MQ才是核心,而MQ的实现又有很多中,如:RabbitMQ、Kafka。这些不同的实现涉及不同的业务需求场景,但其核心思想都是MQ。

所以,要了解RabbitMQ,就需要先弄明白什么是MQ(Message Queue)。

看完描述简介,我问了自己一个问题:

应该至少包含三部分吧:

1,消息发送(生产者);

2,消息处理;

3,消息接收(消费者)。

我第一时间想到的如下几个场景:

1,公共变量的设置和使用;

2,前端技术中对cookie和localstorage的设置和使用;

3,对>

转自: >

rabbitmq是建立在AMQP上的企业消息系统。

以生产者消费者为模型而存在的一个消息队列

1、解耦

这是一个天然的解耦,实现了应用程序不再通过接口,你只需要调用消息队列的接口把结果存放在消息队列即可。

2、异步

一个同步的程序执行,通过消息队列,即可实现异步 *** 作,而不必等待结果返回。在应对一些大并发中,起着很重要的作用

如下图

这里就只有一个队列而已,生产者生产消费,放入到队列中,消费者进行消息消费。

这个能实现多个消费者之间进行消费的公平分发,消息者们可以通过自身的负载进行设置分发频率,比如。a消费者因为一些机器配置等的问题,导致消息没有被立即消费掉,堆积了很多消息,消费者就可以通过设置告诉rabbitmq控制分发频率,别一直发了。这其实就是类似能者多劳的意思。

如下图所示

上面的几种类型,都是消息只能发送到指定的queue中,但是想要类似广播的效果,发给所有消费者,或者像组播的形式,发送给某些特定的消费者。这时候就需要用到exchange了。

1、fanout 所有bind到此exchange的queue都可以接收消息

2、direct: 通过routingKey和exchange决定的那个唯一的queue可以接收消息

3、topic:所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息

表达式符号说明:

4、headers: 通过headers 来决定把消息发给哪些queue

如下图所示

这其实就是direct组播模式,设置好exchange交换机的类型,转发的时候,会检查队列中的routingkey值,如果和消息的关键字相同则转发,否则丢弃

这是topic模式,这个其实和上面一个转发有点类似,但是这个支持模糊匹配,

前言

开源社区有好多优秀的队列中间件,比如RabbitMQ和Kafka,每个队列都貌似有其特性,在进行工程选择时,往往眼花缭乱,不知所措。对于RabbitMQ和Kafka,到底应该选哪个?

RabbitMQ架构

概念

RabbitMQ是一个分布式系统

broker:每个节点运行的服务程序,功能为维护该节点的队列的增删以及转发队列 *** 作请求。

master queue:每个队列都分为一个主队列和若干个镜像队列。

mirror queue:镜像队列,作为master queue的备份。在master queue所在节点挂掉之后,系统把mirror queue提升为master queue,负责处理客户端队列 *** 作请求。注意,mirror queue只做镜像,设计目的不是为了承担客户端读写压力。

如上图所示,集群中有两个节点,每个节点上有一个broker,每个broker负责本机上队列的维护,并且borker之间可以互相通信。集群中有两个队列A和B,每个队列都分为master queue和mirror queue(备份)。那么队列上的生产消费怎么实现的呢?

队列消费

如上图有两个consumer消费队列A,这两个consumer连在了集群的不同机器上。RabbitMQ集群中的任何一个节点都拥有集群上所有队列的元信息,所以连接到集群中的任何一个节点都可以,主要区别在于有的consumer连在master queue所在节点,有的连在非master queue节点上。

因为mirror queue要和master queue保持一致,故需要同步机制,正因为一致性的限制,导致所有的读写 *** 作都必须都 *** 作在master queue上(想想,为啥读也要从master queue中读?和数据库读写分离是不一样的。),然后由master节点同步 *** 作到mirror queue所在的节点。即使consumer连接到了非master queue节点,该consumer的 *** 作也会被路由到master queue所在的节点上,这样才能进行消费。

队列生产

原理和消费一样,如果连接到非 master queue 节点,则路由过去。

不足

由于master queue单节点,导致性能瓶颈,吞吐量受限。虽然为了提高性能,内部使用了Erlang这个语言实现,但是终究摆脱不了架构设计上的致命缺陷。

Kafka

说实话,Kafka我觉得就是看到了RabbitMQ这个缺陷才设计出的一个改进版,改进的点就是:把一个队列的单一master变成多个master,即一台机器扛不住qps,那么我就用多台机器扛qps,把一个队列的流量均匀分散在多台机器上不就可以了么?注意,多个master之间的数据没有交集,即一条消息要么发送到这个master queue,要么发送到另外一个master queue。

这里面的每个master queue 在Kafka中叫做Partition,即一个分片。一个队列有多个主分片,每个主分片又有若干副分片做备份,同步机制类似于RabbitMQ。

如上图,我们省略了不同的queue,假设集群上只有一个queue(Kafka中叫Topic)。每个生产者随机把消息发送到主分片上,之后主分片再同步给副分片。

队列读取的时候虚拟出一个Group的概念,一个Topic内部的消息,只会路由到同Group内的一个consumer上,同一个Group中的consumer消费的消息是不一样的;Group之间共享一个Topic,看起来就是一个队列的多个拷贝。所以,为了达到多个Group共享一个Topic数据,Kafka并不会像RabbitMQ那样消息消费完毕立马删除,而是必须在后台配置保存日期,即只保存最近一段时间的消息,超过这个时间的消息就会从磁盘删除,这样就保证了在一个时间段内,Topic数据对所有Group可见(这个特性使得Kafka非常适合做一个公司的数据总线)。队列读同样是读主分片,并且为了优化性能,消费者与主分片有一一的对应关系,如果消费者数目大于分片数,则存在某些消费者得不到消息。

由此可见,Kafka绝对是为了高吞吐量设计的,比如设置分片数为100,那么就有100台机器去扛一个Topic的流量,当然比RabbitMQ的单机性能好。

总结

本文只做了Kafka和RabbitMQ的对比,但是开源队列岂止这两个,ZeroMQ,RocketMQ,JMQ等等,时间有限也就没有细看,故不在本文比较范围之内。

所以,别再被这些五花八门的队列迷惑了,从架构上找出关键差别,并结合自己的实际需求(比如本文就只单单从吞吐量一个需求来考察)轻轻松松搞定选型。最后总结如下:

吞吐量较低:Kafka和RabbitMQ都可以。

吞吐量高:Kafka。

以上就是关于面试官:如何保证RocketMQ/RabbitMQ消息数据100%不丢失全部的内容,包括:面试官:如何保证RocketMQ/RabbitMQ消息数据100%不丢失、前端工程师认识RabbitMQ的过程、即时通信之 - RabbitMQ(基于socket)基础概念详细介绍等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/10180133.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-06
下一篇 2023-05-06

发表评论

登录后才能评论

评论列表(0条)

保存