前言

之前我们一起了解了使用RocketMQ事务消息解决生产者发送消息时消息丢失的问题,但使用了事务消息后消息就一定不会丢失了吗,肯定是不能保证的。

因为虽然我们解决了生产者发送消息时候的消息丢失问题,但也只是保证Broker正确的接收到了消息,实际上接收到的消息会保存在os cache中,如果此时broker机器突然宕机,os cache中的消息数据就丢失掉了。

而且就算是os cache中的消息已经刷盘到了磁盘中,如果磁盘突然就坏了,消息是不是也就丢失了。

所以我们还要考虑Broker如何保证消息不丢失。

Broker的消息丢失解决方案

说到这里,我们就进入主题了,首先解决临时存在os cache,而未刷新到磁盘导致的消息丢失问题,那么如何解决呢?

看过之前系列文章的小伙伴都知道,Broker是有两种刷盘机制的,同步刷盘和异步刷盘,详细内容可以回顾一下这篇文章:深入研究Broker是如何持久化的

解决的方式就是把异步刷盘改为同步刷盘,具体操作就是修改一下broker的配置文件,将其中的flushDiskType配置设置为:SYNC_FLUSH,默认它的值是ASYNC_FLUSH,即异步刷盘。

调整为同步刷盘后,只要MQ告诉我们消息发送成功了,那么就说明消息已经在磁盘中了。

接下来就要解决磁盘坏了导致的消息丢失问题了。

这个问题其实也很好解决,只要我们使用RockerMQ的高可用集群模式就可以了,也就是说如果返回消息发送成功的响应,那就代表Master Broker已经把数据同步到了Slave Broker中,保证数据有多个备份。

这样一来就算是Master Broker突然宕机 ,也可以通过Dledger技术进行主从的自动切换,使用我们备份的数据,这其中的原理我们已经讲过了,小伙伴们可以自己去复习回顾一下。Dledger是如何实现主从自动切换的

Consumer的消息丢失解决方案

到这里,我们已经确保了生产者和Broker的消息不会丢失了,那么消费者处理消息的时候会不会导致消息丢失呢?

答案是肯定的。

比如说我们的积分系统拿到了消息,还未执行该执行的操作,先返回给broker这条消息的offset,说这条消息已经处理过了。然后突然宕机了,这就导致mq认为这条消息已经处理过了,而实际并没有处理,所以这条消息就丢失掉了。

对于Kafka和RabbitMQ来讲,默认的消费模式就是上边这种自动提交的模式,所以是有可能导致消息丢失掉的。

而RocketMQ的消费者有点不一样,它本身就是需要手动返回消息处理成功的响应的。

所以其实Consumer的消息丢失解决方案也很简单,就是将自动提交改为手动提交

消息零丢失方案的优缺点分析

如果在系统中落地一套消息零丢失的方案,无论什么场景都保证消息的可靠性,这似乎听起来不错,这也是它的优点所在,保证系统的数据都是正确的,不会有丢失的情况。

但它有什么缺点呢?

首先,引入了这套解决方案之后,系统的复杂度变高了,想想事务消息的实现方式你肯定会这么觉得。

而且比较严重的缺点是,它会导致系统的性能严重的下降,比如原来每秒可以处理好几万条的消息,结果在引入消息零丢失这套方案之后,可能每秒就只能处理几千条消息了。

其实只要随便思考一下,就可以想明白这个问题。

事务消息的复杂性导致生产消息的过程耗时更久了,同步刷盘的策略导致写入磁盘后才返回消息,自然也会增加耗时,而消费者如果异步的处理消息,直接返回成功,整个流程的速度会更快。

所以说引入这么一套消息零丢失的方案,对于性能的影响还是很大的。

总结

其实关于消息零丢失的方案无外乎就这么多,所以本篇文章内容不是很多。

既然我们刚才聊了消息零丢失方案的缺点,那么就继续讨论一下,究竟什么场景下需要引入这套方案吧。

王子给大家介绍一下自己的想法。

一般我们对于跟金钱、交易以及核心数据相关的系统和核心链路,可以采用这套方案。

比如说我们文章中举的例子:支付系统、订单系统、积分系统。

而对于其他的没那么核心的场景,丢失一些数据问题也不大,就不应该采用这套方案了,或者说可以做一些简化,比如事务消息改成失败重试几次的机制,刷盘策略改为异步刷盘。

那么小伙伴们在平时的工作中,这套方案是怎么应用到生产环境中的呢?欢迎留言讨论。

往期文章推荐:

深入研究RocketMQ生产者发送消息的底层原理

深入研究Broker是如何持久化的

Dledger是如何实现主从自动切换的

深入研究RocketMQ消费者是如何获取消息的

RocketMQ的消息是怎么丢失的

RocketMQ消息丢失解决方案:事务消息

RocketMQ消息丢失解决方案:同步刷盘+手动提交的更多相关文章

  1. RocketMQ消息丢失解决方案:事务消息

    前言 上篇文章,王子通过一个小案例和小伙伴们一起分析了一下消息是如何丢失的,但没有提出具体的解决方案. 我们已经知道发生消息丢失的原因大体上分为三个部分: 1.生产者发送消息到MQ这一过程导致消息丢失 ...

  2. RocketMQ 消息丢失场景分析及如何解决

    生产者产生消息发送给RocketMQ RocketMQ接收到了消息之后,必然需要存到磁盘中,否则断电或宕机之后会造成数据的丢失 消费者从RocketMQ中获取消息消费,消费成功之后,整个流程结束 1. ...

  3. 探秘 RocketMQ 消息持久化机制

    我们知道 RocketMQ 是一款高性能.高可靠的分布式消息中间件,高性能和高可靠是很难兼得的.因为要保证高可靠,那么数据就必须持久化到磁盘上,将数据持久化到磁盘,那么可能就不能保证高性能了. Roc ...

  4. 【RocketMQ】消息的刷盘机制

    刷盘策略 CommitLog的asyncPutMessage方法中可以看到在写入消息之后,调用了submitFlushRequest方法执行刷盘策略: public class CommitLog { ...

  5. RabbitMQ,RocketMQ,Kafka 事务性,消息丢失和消息重复发送的处理策略

    消息队列常见问题处理 分布式事务 什么是分布式事务 常见的分布式事务解决方案 基于 MQ 实现的分布式事务 本地消息表-最终一致性 MQ事务-最终一致性 RocketMQ中如何处理事务 Kafka中如 ...

  6. Rocket重试机制,消息模式,刷盘方式

    一.Consumer 批量消费(推模式) 可以通过 consumer.setConsumeMessageBatchMaxSize(10);//每次拉取10条 这里需要分为2种情况 Consumer端先 ...

  7. 面试官再问我如何保证 RocketMQ 不丢失消息,这回我笑了!

    最近看了 @JavaGuide 发布的一篇『面试官问我如何保证Kafka不丢失消息?我哭了!』,这篇文章承接这个主题,来聊聊如何保证 RocketMQ 不丢失消息. 0x00. 消息的发送流程 一条消 ...

  8. rocketmq刷盘过程

     本文基于rocketmq4.0版本,结合CommitlLog的刷盘过程,对消息队列的刷盘过程源码进行分析,进而对RocketMQ的刷盘原理和过程进行了解.   rocketmq 4.0版本中刷盘类型 ...

  9. RocketMQ中Broker的刷盘源码分析

    上一篇博客的最后简单提了下CommitLog的刷盘  [RocketMQ中Broker的消息存储源码分析] (这篇博客和上一篇有很大的联系) Broker的CommitLog刷盘会启动一个线程,不停地 ...

随机推荐

  1. Java Web学习(十一)Java过滤器

    一.引言 上一篇文章学习了java三大器的拦截器,拦截器主要是针对于action请求进行拦截处理的,那么对于requst的一些信息如果在调用前,想先进行过滤和处理,那么就要使用到第二个神器,也就是本文 ...

  2. gcc g++ 安装与配置 入门详解 - 精简归纳

    gcc g++ 安装与配置 入门详解 - 精简归纳 JERRY_Z. ~ 2020 / 9 / 24 转载请注明出处!️ 目录 gcc g++ 安装与配置 入门详解 - 精简归纳 一.下载MinGW ...

  3. 利用Z.Expressions.Eval表达式求值

    Z.Expression.Eval是一个开源的(OpenSource),可扩展的(Extensible),超轻量级(Super lightweight)的公式化语言解析执行工具包. 使用方法:1.从n ...

  4. mysql load_file()

    本地mysql注入读取配置文件 遇到的问题 简单记录一下. 本地测试时,读取文件发现无论怎样都返回为NULL. >> select load_file('c:/xx/xx/xx/x.txt ...

  5. OSPF及实验

    OSPF:Open Shortest Path First,最短路径优先1)基本概念:标准的LS型协议--共享拓扑组播更新:224.0.0.5/6触发更新,存在周期更新  30minOSPF是跨层封装 ...

  6. ARM架构下的Docker环境,OpenJDK官方没有8版本镜像,如何完美解决?

    为什么需要ARM架构下的OpenJDK8的Docker镜像? 对现有的Java应用,之前一直运行在x86处理器环境下,编译和运行都是JDK8,如今在树莓派的Docker环境运行(或者其他ARM架构电脑 ...

  7. JUC并发编程--AQS

    转自: https://www.jianshu.com/p/d8eeb31bee5c 前言 在java.util.concurrent.locks包中有很多Lock的实现类,常用的有Reentrant ...

  8. Java知识系统回顾整理01基础06数组02初始化数组

    一.分配空间与赋值分步进行 分配空间与赋值分步进行 public class HelloWorld { public static void main(String[] args) { int[] a ...

  9. c++中sprintf和sprintf_s的区别

    参考:https://blog.csdn.net/qq_37221466/article/details/81140901 sprintf_s是sprintf的安全版本,指定缓冲区长度来避免sprin ...

  10. 对ACE和ATL积分

    下载source code - 39.66 KB 介绍 这篇文章展示了一种结合ACE和ATL的方法.它不打算作为功能演示,而是作为一个小型的"入门"解决方案,展示实现此目标的可行方 ...