RocketMQ常见问题分析

目录

1. RocketMQ如何保证消息不丢失

1.1 分析消息丢失场景

1.2 解决方案

1.2.1 保证消息生产不丢失

1.2.1.1 生产消息时不使用单向发送消息发送模式

1.2.1.2 生产者使用事务消息机制

1.2.2 保证消息存储不丢失

1.2.3 保证消息消费不丢失

1.2.4 RocketMQ特有的问题,NameServer挂了如何保证消息不丢失?

2. 使用RocketMQ如何快速处理积压消息?

2.1 如何确定RocketMQ有大量的消息积压?

2.2 如何处理大量积压的消息?


1. RocketMQ如何保证消息不丢失

1.1 分析消息丢失场景

下图是一个MQ的通用场景图:

从上图中,我们可以得到,消息流转的4个环节

  • 1:生产者发送消息到MQ服务
  • 2:主从同步
  • 3:同步磁盘
  • 4:消费者消费消息

        其中1、3、4这3个环节都是跨网络的,而跨网络,那就可能会丢失消息。

        关于3这个环节,通常MQ存盘时都会先写入操作系统的缓存page cache中,然后再由操作异步的将消息写入硬盘。这个中间有个时间差,就可能会造成消息丢失。如果服务挂了,缓存中还没有来得及写入硬盘的消息就会丢失。

1.2 解决方案

        接下来我们看一下,当我们用RocketMQ时,如何解决上述4个环节丢失消息的场景;

1.2.1 保证消息生产不丢失

1.2.1.1 生产消息时不使用单向发送息发送模式

        我们想一下,消息生产时为什么会丢失消息。当生产者发送消息时,如果出现了网络抖动或者消息异常,那么消息就有可能丢失。那么这个问题解决思路是什么呢?其实简单的来说就是4个字:应答重试

        怎么理解应答重试呢? 其实就是当生产者发送消息成功后返回成功确认消息,如果发送失败,客户端就尝试自动重试,避免网络抖动导致消息发送不成功。如果超过一定超时时间还是失败,那就抛出异常,由开发者自己在应用层面进行处理,手动重试发送 或者 记录失败。

     不过我们需要特别注意是,RocketMQ支持多种「消息类型」,但是并不是对所有「消息类型」 都会有应答重试机制(消息确认机制和失败重试机制)。

        RocketMQ生产消息时,支持多种「消息类型」和「消息发送模式」。有兴趣同学可以参考org.apache.rocketmq.client.producer.MQProducer这个接口定义即可。接下来我们看一下rocketMQ的消息类型和消息发送模式又哪些以及各自的特点:

消息类型:

  • 普通消息:发送普通消息,异常时默认重试。
  • 普通有序消息:发送普通有序消息,通过指定「消息筛选器selector」,动态决定发送哪个队列。异常默认不重试,可以用户自己重试,并发送到其他队列。
  • 严格有序消息:发送严格有序消息,通过指定队列,保证严格有序,异常默认不重试。

消息发送模式:

  • 同步:调用发送消息方法后,同步阻塞,直到返回SendResult。配置retryTimesWhenSendFailed重试次数。
  • 异步:调用发送消息方法后,立即返回,发送结果会通过开发者自己注册的回调函数SendCallback进行处理。配置retryTimesWhenSendAsyncFailed重试次数。
  • 单向发送:这种方法完全不关心发送后的返回结果。显然,它具有最大吞吐量,但也存在消息丢失的潜在风险。

        消息类型 和 消息发送模式 是 N * M 的关系,所以存在9种不同组合,RocketMQ也是定义了9种不同接口方法。
这9种方法里面,涉及到「单向发送」模式的3种方法,都是不可靠的,存在丢失消息的风险。其他发送消息的模式和消息类型,可以通过 消息确认、mq-client自动「失败重试机制」、业务自定义重试 等方式,确保消息发送不丢失。

1.2.1.2 生产者使用事务消息机制

        org.apache.rocketmq.client.producer.MQProducer还定义了「事务消息」的发送模式,接下来我们理解一下事务机制;因为RocketMQ的事务消息机制就是为了保证零丢失来设计的,并且经过阿里的 验证,肯定是非常靠谱的。所以事务机制也可以报纸生产者生产消息时不丢失消息。接下来我们用一个场景来简单分析一下事务消息机制是如何保证消息不丢失的。我们看下下面这个流程图:

1、为什么要发送个half消息?有什么用?

这个half消息是在订单系统进行下单操作前发送,并且对下游服务的消费者是不可见的。那这个消息的作用更多的体现在确认RocketMQ的服务是否正常。相当于嗅探下RocketMQ服务是否正常,并且通知RocketMQ,我马上就要发一个很重要的消息了,你做好准备。

2.half消息如果写入失败了怎么办?

如果没有half消息这个流程,那我们通常是会在订单系统中先完成下单,再发送消息给MQ。这时候写入消息到MQ如果失败就会非常尴尬了。而half消息如果写入失败,我们就可以认为MQ的服务是有问题的,这时,就不能通知下游服务了。我们可以在下单时给订单一个状态标记,然后等待MQ服务正常后再进行补偿操作,等MQ服务正常后重新下单通知下游服务。

3.订单系统写数据库失败了怎么办?

这个问题我们同样比较下没有使用事务消息机制时会怎么办?如果没有使用事务消息,我们只能判断下单失败,抛出了异常,那就不往MQ发消息了,这样至少保证不会对下游服务进行错误的通知。但是这样的话,如果过一段时间数据库恢复过来了,这个消息就无法再次发送了。当然,也可以设计另外的补偿机制,例如将订单数据缓存起来,再启动一个线程定时尝试往数据库写。而如果使用事务消息机制,就可以有一种更优雅的方案。

如果下单时,写数据库失败(可能是数据库崩了,需要等一段时间才能恢复)。那我们可以另外找个地方把订单消息先缓存起来(Redis、文本或者其他方式),然后给RocketMQ返回一个UNKNOWN状态。这样RocketMQ就会过一段时间来回查事务状态。我们就可以在回查事务状态时再尝试把订单数据写入数据库,如果数据库这时候已经恢复了,那就能完整正常的下单,再继续后面的业务。这样这个订单的消息就不会因为数据库临时崩了而丢失。

4.half消息写入成功后RocketMQ挂了怎么办?

我们需要注意下,在事务消息的处理机制中,未知状态的事务状态回查是由RocketMQ的Broker主动发起的。也就是说如果出现了这种情况,那RocketMQ就不会回调到事务消息中回查事务状态的服务。这时,我们就可以将订单一直标记为"新下单"的状态。而等RocketMQ恢复后,只要存储的消息没有丢失,RocketMQ就会再次继续状态回查的流程。

5.下单成功后如何优雅的等待支付成功?

在订单场景下,通常会要求下单完成后,客户在一定时间内,例如10分钟,内完成订单支付,支付完成后才会通知下游服务进行进一步的营销补偿。

如果不用事务消息,那通常会怎么办?

最简单的方式是启动一个定时任务,每隔一段时间扫描订单表,比对未支付的订单的下单时间,将超过时间的订单回收。这种方式显然是有很大问题的,需要定时扫描很庞大的一个订单信息,这对系统是个不小的压力。

那更进一步的方案是什么呢?是不是就可以使用RocketMQ提供的延迟消息机制。往MQ发一个延迟1分钟的消息,消费到这个消息后去检查订单的支付状态,如果订单已经支付,就往下游发送下单的通知。而如果没有支付,就再发一个延迟1分钟的消息。最终在第十个消息时把订单回收。这个方案就不用对全部的订单表进行扫描,而只需要每次处理一个单独的订单消息。

那如果使用上了事务消息呢?我们就可以用事务消息的状态回查机制来替代定时的任务。在下单时,给Broker返回一个UNKNOWN的未知状态。而在状态回查的方法中去查询订单的支付状态。这样整个业务逻辑就会简单很多。我们只需要配置RocketMQ中的事务消息回查次数(默认15次)和事务回查间隔时间(messageDelayLevel),就可以更优雅的完成这个支付状态检查的需求。

6、事务消息机制的作用

整体来说,在订单这个场景下,消息不丢失的问题实际上就还是转化成了下单这个业务与下游服务的业务的分布式事务一致性问题。而事务一致性问题一直以来都是一个非常复杂的问题。而RocketMQ的事务消息机制,实际上只保证了整个事务消息的一半,他保证的是订单系统下单和发消息这两个事件的事务一致性,而对下游服务的事务并没有保证。但是即便如此,也是分布式事务的一个很好的降级方案。目前来看,也是业内最好的降级方案。

1.2.2 保证消息存储不丢失

1.2.3 保证消息消费不丢失

1.2.4 RocketMQ特有的问题,NameServer挂了如何保证消息不丢失?

2. 使用RocketMQ如何快速处理积压消息?

2.1 如何确定RocketMQ有大量的消息积压?

2.2 如何处理大量积压的消息?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/576722.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Echarts legend属性使用

Echarts的legend属性是对图例组件的相关配置 而legend就是Echarts图表中对图形的解释部分: 其中legend自身常用的配置属性如下: orient 设置图例的朝向 属性值: vertical // 垂直显示 或者 horizontal // 水平显示 legend: {orient: ver…

Pandas有了平替Polars

Polars是一个Python数据处理库,旨在提供高性能、易用且功能丰富的数据操作和分析工具。它的设计灵感来自于Pandas,但在性能上更加出色。 Polars具有以下主要特点: 强大的数据操作功能:Polars提供了类似于Pandas的数据操作接口&am…

涵盖多种功能,龙讯旷腾Module第七期:超快动力学过程

Module是什么 在PWmat的基础功能上,我们针对用户的使用需求开发了一些顶层模块(Module)。这些Module中的一部分是与已有的优秀工具的接口,一部分是以PWmat的计算结果为基础得到实际需要的物理量,一部分则是为特定的计…

ctf web赛道基础 万字笔记

一、SQL注入(mysql): 基本语法 判断列数 order by 3 查询所有数据库: select group_concat(schema_name) from information_schema.schemata 查询当前数据库的所有表: select group_concat(table_name) from informa…

12.鸿蒙HarmonyOS App(JAVA) page的隐式跳转

跳转到指定Page的指定AbilitySlice MainAbilitySlice按钮触发事件: btn.setClickedListener(component -> { Intent _intent new Intent(); Operation operation new Intent.OperationBuilder() .withBundleName(…

关于Windows11画图板出现马赛克问题

参考博客链接: Win11新版画图板问题 一、问题描述 新版win11画图板使用橡皮擦,或者框选图片会出现这种马赛克的问题 二、问题解决 1.先点击 “层” 2.点击 “” 3.点击出现的这个层 现在就可以正常的使用画图板啦 如果想要取消右边的那一栏,…

git集成github(二)-- 遇见的问题与解决方法

1、share project on github时,弹出Cannot load information for github.com/zouxiaoya:Connection reset问题。 解决方法:pycharm-->setting-->version control-->github中,删除掉当前用户,点击reset重置即可。 2、 pus…

JavaScript中的prototype和_proto_的关系是什么

JavaScript中的prototype和_proto_的关系是什么 __proto__ 是 JavaScript 中对象的一个内部属性,它指向该对象的原型。JavaScript 中每个对象都有一个 __proto__ 属性,通过它可以访问对象的原型。prototype 是函数对象特有的属性,每个函数都…

深入了解 Git 分支合并冲突解决步骤

目录 前言1 检测合并冲突2 手动解决冲突2.1 打开冲突文件2.2 手动解决冲突 3 标记解决后的文件4 完成合并5 提交合并后的内容6 验证合并结语 前言 在协作开发中,当不同分支对同一文件的相同位置进行修改时,往往会出现合并冲突。这些冲突需要开发者手动介…

使用四层for循环求得1、2、3、4组成的互不相关的三位数

一、思想 使用四层for循环进行循环遍历,进行判断,然后根据规则在最里侧的for循环输出这些三位数。 二、代码 public class ThreeDigit {public static void main(String[] args){int[] a {1,2,3,4};System.out.println("满足条件的三位数是&…

一盒晶圆只有25片吗?

没有答案,可能是实践的标准。后来在工作过程中发现还有13片的,个人认为研究这个问题不如多看看foup! 晶圆载具用于硅片生产、晶圆制造以及工厂之间晶圆的储存、传送、运输以及防护。晶圆载具种类很多,如FOUP用于晶圆制造工厂中晶圆…

【MySQL】数据库索引(简单明了)

🍎个人博客:个人主页 🏆个人专栏: 数 据 库 ⛳️ 功不唐捐,玉汝于成 目录 前言: 正文: 索引的类型 创建索引 1. 创建单列索引 2. 创建复合索引 索引的优势 索引的劣势 示例 注意…

软考高项通过人数增加70%!改为机考难度降低了?

最近,河北省人事考试网陆续发布了“2023年度上半年和下半年计算机技术与软件专业技术资格(水平)考试河北省合格人员公示名单”。从名单来看,2023年度下半年软考通过人数较上半年有显著增加。 一、河北软考合格人数统计 2023年上半…

mysql原理--基于成本的优化

1.什么是成本 我们之前老说 MySQL 执行一个查询可以有不同的执行方案,它会选择其中成本最低,或者说代价最低的那种方案去真正的执行查询。不过我们之前对 成本 的描述是非常模糊的,其实在 MySQL 中一条查询语句的执行成本是由下边这两个方面组…

SpringMVC核心处理流程梳理

1、处理流程图展示 当我拿出这张图,阁下又该如何应对呢?执行流程是不是一目了然了。 2、DispatcherServlet:中央处理器或者中央调度器 下图官方的解释应该最完善了。 3、SpringMVC三大核心组件 HandlerMapping 处理器映射器,…

BUUCTF——Reverse——内涵的软件

1、题目 2、工具 Exeinfo PE:查壳工具。IDA:是一款功能强大的反汇编工具,用于分析和逆向工程二进制文件。 3、方法 下载文件,得到一个.exe文件。 打开该文件,尝试输入Y和N。 用Exeinfo PE查询该文件是否加了壳。 可…

基于图搜索的自动驾驶规划算法 - BFS,Dijstra,A*

本文将讲解BFS,Dijstra,A*,动态规划的算法原理,不正之处望读者指正,希望有兴趣的读者能在评论区提出一些这些算法的面试考点,共同学习,一起进步 0 图论基础 图有三种:无向图、有向…

11.Go 列表

列表是一种非连续的存储容器,由多个节点组成,节点通过一些变量记录彼此之间的关系,列表有多种实现方法,如单链表、双链表等。 在Go语言中,列表使用container/list包来实现,内部的实现原理是双链表&#xf…

物理模拟重力 斜抛运动计算 抛物线计算

物理模拟重力 斜抛运动计算 抛物线计算 一、介绍二、原理三、实现如下PhysicsUtil.cs 工具类Missile.cs 四、资源分享 一、介绍 模拟Unity原始重力系统进行重写,可是实现发射到指定目标位置并能继续当前力进行自身的弹力与摩擦继续运动 二、原理 将Unity原始不受控…

​一个人成长最快的方式

一个人成长最快的方式就是:保持阅读,向行业的专家学习,在实践中不断的复盘总结,循环这三点,没有学不好的东西。基于此,推荐一些在产品、设计领域的专家,关注他们,学习他们&#xff0…