前言

之前我们一起了解了使用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. Laravel Exception结合自定义Log服务的使用

    Laravel Exception结合自定义Log服务的使用 第一部分:laravel关于错误和异常的部分源码 第二部分:自定义异常的使用(结合serviceprovider monolog elas ...

  2. Redis学习(三)java使用redis

    一.操作步骤 Redis除了命令行操作以外,还可以通过java代码进行操作,流程如下: 下载Jedis依赖包,并丢入工程中合适的位置 在Maven中引入redis的包 <!--引入redis包- ...

  3. Redis学习(二)redis的特点

    一.Redis的特性 Redis是基于内存,常用作于缓存的技术 Redis实现的是分布式缓存,如果有多台实例(机器)的话,每个实例都共享一份缓存,缓存具有一致性. 常见的性能问题一般都是由于数据库(磁 ...

  4. 破壳漏洞(CVE-2014-6271)分析

    受影响版本:GNU Bash 4.3及之前版本 影响范围:主流的Linux和MacOSX操作系统,与bash交互的各种应用程序,如HTTP,FTP,DHCP等等. 漏洞原理及POC验证: 1.bash ...

  5. 总结一下,selenium 自动化流程如下

    自动化程序调用Selenium 客户端库函数(比如点击按钮元素) 客户端库会发送Selenium 命令 给浏览器的驱动程序 浏览器驱动程序接收到命令后 ,驱动浏览器去执行命令 浏览器执行命令 浏览器驱 ...

  6. 创建Vue项目及封装axios

    1. 始vue化项目 https://www.cnblogs.com/xiaonq/p/11027880.html vue init webpack deaxios # 使用脚手架创建项目 deaxi ...

  7. golang go语言 实现链表

    package main import ( "errors" "fmt" "strconv" ) type List struct { Le ...

  8. 《kubernetes + .net core 》dev ops部分

    目录 1.kubernetes 预备知识 1.1 集群资源 1.1.1 role 1.1.2 namespace 1.1.3 node 1.1.4 persistent volume 1.1.5 st ...

  9. SQL实战——03. 查找各个部门当前(to_date='9999-01-01')领导当前薪水详情以及其对应部门编号dept_no

    查找各个部门当前(to_date='9999-01-01')领导当前薪水详情以及其对应部门编号dept_noCREATE TABLE `dept_manager` (`dept_no` char(4) ...

  10. Java知识系统回顾整理01基础04操作符07Scanner

    一.Scanner 需要用到从控制台输入数据时,使用Scanner类. 二.使用Scanner读取整数 注意: 使用Scanner类,需要在最前面加上 import java.util.Scanner ...