专栏首页dotNET知音RabbitMq如何确保消息不丢失

RabbitMq如何确保消息不丢失

上篇写了掌握Rabbitmq几个重要概念,从一条消息说起,这篇来总结关于消息丢失让人头痛的事情。网络故障、服务器重启、硬盘损坏等都会导致消息的丢失。消息从生产到消费主要结果以下几个阶段如下图。

①生产阶段,生产者创建消息,经过网络发送到rabbit服务器

②消息存储阶段,首先被发送到交换器然后经过路由算法,到达队列,等待被拉取消费

③消费阶段,消费者经过网络从rabbit服务器拉取消息进行消费

这三个阶段都有可能消息丢失,下面一一分析。

消息存储阶段

正常情况下,我们使用BasicPublish方法发送消息到交换器上然后路由到队列上面,消费者还没进行消费,此时服务器重启了(队列、交换器使用默认的创建方式),会发生什么?答案是:消息丢失。原因很简单:消息在内存中,没有刷盘,并且,他们默认是非持久化的,服务重启之后,它们需要重新创建,消息自然就丢失!

还好,Rabbit提供持久化的机制,队列、交换器创建的时候,durable属性设置为true,同时消息投递模式(delivery mode)设置为2,则消息标记成持久化。这样可以避免服务器重启消息丢失的情况。

发送阶段

由于发布操作不返回任何信息给生产者,那你怎么知道服务器是否已经持久化了持久消息到硬盘呢?服务器可能在把消息写入磁盘前就宕机了,消息因此而丢失!

有。)

Rabbit提供两中解决方案,事务,但是性能会大打折扣,而且会使生产者应用程序产生同步。生产环境一般不会采用;另外一种方案是确认模式。也很简单,消息路由给所有匹配的订阅队列中,之后会异步的告之生产者。使用channel.ConfirmSelect()方法,使信道开启确认模式。然后注入两个回调函数,ack和nack事件。

channel.BasicAcks += (sender, ev) =>
                {
                    Console.WriteLine("消息已经确认收到" + ev.DeliveryTag);

                };

                channel.BasicNacks += (sender, ev) =>
                {
                    Console.WriteLine("消息未确认" + ev.DeliveryTag);
                };

消费阶段

你可能会问,消费端消息怎么会丢失呢?Rabbitmq提供自动和手动确认消息,然后消息从队列中移除。如果autoAck为true,自动确认模式,服务器就会在消息发给消费端后自动将其出队。如果因为某些原因连接中断了,或者你的消费端应用发生了故障,那么消息就会丢失!

通过把AutoAck设置为false,手工确认,告知服务器,消息已经处理了,可以进行消息出队删除。

 channel.BasicConsume(queue: queueName,
                                     autoAck: false,
                                     consumer: consumer);
 consumer.Received += (model, ea) =>
                {
                    //dosometing
                    channel.BasicAck(ea.DeliveryTag, false);//确认
                };

小结:如果做了以上的处理,那么消息就不会跟你躲猫猫了。这里有性能的问题,消息持久化,是要刷到磁盘上的会影响投递速度,并且消息确认也会影响到消息投递速度。不基本上能够满足需求了。如果不能满足性能需求,可以使用其他方法,比如 在每次发送消息的时候,都包含应答队列的名称,这样消费者就可以回发应答以确认接受到了。如果消息应答未在合理时间范围内到达,生产者就重新发送消息。

本文分享自微信公众号 - dotNET知音(AAshiyou),作者:李明成

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-09-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 掌握Rabbitmq几个重要概念,从一条消息说起

    RabbitMQ 是功能强大的开源消息代理。根据官网称:也是使用量最广泛的消息队列。就像他的口号“Messaging that just works”,开箱即用...

    李明成
  • 【翻译】.NET 5中的性能改进

    在.NET Core之前的版本中,其实已经在博客中介绍了在该版本中发现的重大性能改进。从.NET Core 2.0到.NET Core 2.1到.NET Cor...

    李明成
  • .NetCore2.1升级到3.1记录

    以为缺少对应的包,然后去nuget安装时发现 最新版本是2.2 ,跟.NETcore web 项目引用的版本不一样。

    李明成
  • 消息队列设计1 何时需要

    消息队列通常作为企业IT系统内部通信的核心手段 具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。

    JavaEdge
  • 消息队列设计精要

    消息队列已经逐渐成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。 当今市面上...

    美团技术团队
  • 消费端如何保证消息队列MQ的有序消费

    消息队列,既然是队列就能保证消息在进入队列,以及出队列的时候保证消息的有序性,显然这是在消息的生产端(Producer),但是往往在生产环境中有多个消息的消费端...

    用户1148394
  • ActiveMQ介绍

    1、ActiveMQ服务器工作模型       通过ActiveMQ消息服务交换消息。消息生产者将消息发送至消息服务,消息消费者则从消息服务接收这些消息。这些消...

    小帅丶
  • rtmp规范1.0

    本文为Adobe rtmp规范1.0的中文介绍,其中内容大部分都是翻译自rtmp官方文档rtmp_specification_1.0.pdf

    职场亮哥
  • 消费端如何保证消息队列MQ的有序消费

    消息队列,既然是队列就能保证消息在进入队列,以及出队列的时候保证消息的有序性,显然这是在消息的生产端(Producer),但是往往在生产环境中有多个消息的消费端...

    Java_老男孩
  • 使用消息中间件时,如何保证消息仅仅被消费一次?

    消息中间件使用广泛,常用来削峰填谷、系统解耦、异步处理。异步处理可能是使用的最多的场景了,比如现在的技术博客网站,都采用积分制,用户发表一篇文章后,可以获取想要...

    平头哥的技术博文

扫码关注云+社区

领取腾讯云代金券