如果公司线上系统突然宕机了,怎么才能确保MQ消息不丢失?

news2025/1/16 8:08:49
V-xin:ruyuanhadeng获得600+页原创精品文章汇总PDF

一、写在前面

之前写过一篇文章《项目里接入了MQ消息中间件以后,我摸鱼的时间更长了~》,我们用一个简单易懂的电商场景给大家引入说明了一个消息中间件的使用场景。

同时,我们还基于RabbitMQ的HelloWorld级别的代码,给出了订单服务和仓储服务如何基于MQ中间件收发消息的示例。


二、业务场景回顾

这篇文章,我们来稍微深入探讨一些MQ中间件使用中的基础技术问题。

首先回顾一下上篇文章做出来的一个架构图,看看订单服务和消息服务是如何基于MQ来收发消息的。

我们稍微把这个图细化一点,简单来说就是多个订单服务实例给queue推送消息,多个仓储服务每个消费一部分消息。如下图所示:

在这里插入图片描述

三、意外宕机,问题凸现

假如你线上对MQ技术的使用就到此为止了,那么基本可以跟offer说拜拜了。。。

因为如果是我的话,作为一个面试官就没法继续往下问了。你这个MQ的使用以及理解的深度仅此而已的话,那基本就是刚刚对MQ技术入门的程度。

如果面试官要继续问,完全可以问下面的问题:

  • 那你说说如果仓储服务作为消费者服务,刚收到了一个订单消息,但是在完成消息的处理之前,也就是还没对订单完成仓储调度发货,结果这个仓储服务突然就宕机了,这个时候会发生什么事情?

所以说,大家还是要对这个技术了解的稍微深入一点点,否则随便被问几个问题就完蛋了。

大伙儿先来看看下面的图,感受一下车祸现场。

在这里插入图片描述

RabbitMQ这个中间件默认的一个行为,就是只要仓储服务收到一个订单消息,RabbitMQ就会立马把这条订单消息给标记为删除,这个行为叫做自动ack,也就是投递完成一条消息就自动确认这个消息处理完毕了。

但是接着如果此时仓储服务收到了一个订单消息,但是还没来得及对仓库系统完成商品的调度发货,结果直接就宕机了。

此时,明显这个订单消息就丢失了啊,因为RabbitMQ那里已经没有了。。。

这会导致什么样的尴尬体验呢?就是一个用户支付了8999元,对一个iphone8下了订单,结果呢,死等活等了好几天,就是不见网站上显示他的iphone8在发货。

搞了半天,原因就是他的那个iphone8的订单在仓储服务那里,还没来得及调度发货直接就宕机了,导致这个订单消息就一直丢失了,始终没有给这个用户通知仓库系统进行发货。

这个问题,是不是很尴尬?所以说,技术问题是会严重影响企业的核心业务流程的!

各位小伙伴,还记得上一讲咱们的仓储服务消费消息的代码中,有一行关键的代码:

在这里插入图片描述

这行代码对channel.basicConsume() 方法,传入的第二个参数:true,其实就是一个关键的参数。

这个true就代表了一个核心的含义,他的意思是,RabbitMQ只要把一个消息投递到仓储服务手上,立马就标记这个消息删除了

但是在这个默认的配置之下,要是仓储服务收到一个订单消息,结果还没来得及完成耗时几十秒的仓储调度发货的业务逻辑,结果突然宕机了,那么这个订单消息就永久性丢失了!

找了半天,原来问题的症结在这里啊!大家是不是明白了,上一篇文章最后为什么我会说,这个代码目前为止还有很多的问题。

所以这个时候,我们如果希望不要因为仓储服务的突然宕机导致一条订单消息丢失,就需要改造一下仓储服务消费消息的代码了。

首先,我们需要把那个参数从true改为false,如下代码所示:

在这里插入图片描述

只要修改为false之后,RabbitMQ就不会盲目的投递消息到仓储服务,立马就删除消息了,说白了就是关闭autoAck的行为,不要自作主张的认为消息处理成功了。

接着,我们需要改造一下处理订单消息的代码,如下代码所示。

这段代码,说白了,就是在对订单完成了调度发货之后,在finally代码块中手动执行了ack操作,说我自己已经完成了耗时几十秒的业务逻辑的处理,现在可以手动ack通知RabbitMQ,这个消息处理完毕了。

在这里插入图片描述

此时整个架构运行流程大致看起来跟下面的图那样子。

在这里插入图片描述

架构流程改成上面那样后,就意味着只有完成了仓储调度发货的代码业务逻辑,确保仓库系统收到通知之后,仓储服务才会在代码中手动发送ack消息给RabbitMQ。

此时,RabbitMQ收到了这个ack消息,才会标记对应的订单消息被删除了。

如果说在仓储服务收到了订单消息,但是还没来得及完成仓储调度发货的业务逻辑,那也就绝对不会执行这条订单消息的ack操作,然后RabbitMQ也就不会收到这条订单消息的ack通知。

一旦RabbitMQ发现代表消费者的某个仓储服务实例突然宕机了,而这个仓储服务收到的一些订单消息还没来得及处理,没给自己发送那些消息的ack通知。

此时,RabbitMQ会自动对这条订单消息重发推送给其他在运行中的仓储服务实例,让其他的仓储服务实例去处理这条订单消息。

这样的话,就可以保证这条订单消息不会因为某个仓储服务实例的宕机而丢失,他会确保必须由某个仓储服务实例完成这条订单消息的调度发货处理,然后才会删除那条订单消息。


四、总结 tips

最后再来一张图,大家直观的感受一下:

在这里插入图片描述

好了,各位同学,这篇文章是不是相对稍微深入一点点,让大家了解到了一些使用MQ技术时候要考虑的一些问题?

实际上无论是RocketMQ、Kafka还是RabbitMQ,都有类似的autoAck或者是手动ack的机制。

线上生产环境中运行时,你必须要考虑到消费者服务可能宕机的问题

如果消费者服务没处理完消息就自己宕机了,那么一定会导致部分消息的丢失,进而影响核心业务流程的运转。

因此大家在线上使用MQ时,一定要充分考虑这些潜在问题,同时结合具体的MQ提供的一些API、参数来进行合理设置,确保消息不要随意丢失。

V-xin:ruyuanhadeng获得600+页原创精品文章汇总PDF

另外推荐儒猿课堂的1元系列课程给您,欢迎加入一起学习~

互联网Java工程师面试突击课(1元专享)

SpringCloudAlibaba零基础入门到项目实战(1元专享)

亿级流量下的电商详情页系统实战项目(1元专享)

Kafka消息中间件内核源码精讲(1元专享)

12个实战案例带你玩转Java并发编程(1元专享)

Elasticsearch零基础入门到精通(1元专享)

基于Java手写分布式中间件系统实战(1元专享)

基于ShardingSphere的分库分表实战课(1元专享)

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

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

相关文章

考研英语|传统文化英语高频词汇

目录​​​​​​​ 一. 节日名称 二. 相关节日活动 三. 传统饮食 四. 传统建筑 五. 文学艺术 六. 四大发明 七. 新四大发明 一. 节日名称 1. 春节:Chinese New Years Day / Chinese Lunar New Year / the Spring Festival 2. 除夕:New Years E…

Vue2.0开发之——Vue组件-样式冲突(35)

一 概述 scoped的使用及底层原理使用deep修改子组件中的样式 二 scoped的使用及底层原理 2.1 组件之间的样式冲突问题(修改Left.vue中的h3属性,Right也被修改) 默认情况下,写在 .vue 组件中的样式会全局生效,因此很容易造成多个组件之间的样…

kubelet源码分析 syncLoopIteration(二) plegCh、syncCh

kubelet源码分析 syncLoopIteration(二) plegCh 上一篇:kubelet源码分析 syncLoopIteration(一) configCh 上一篇说了configCh管道的作用,这一篇说一下plegCh管道。这个管道主要是监听容器运行时状态的&…

搭建Python环境

搭建Python环境 文章目录搭建Python环境需要安装的环境:安装Python1)找到官网2)找到下载页面3)双击安装包4)运行 hello world安装 PyCharm1)找到官方网站2)找到下载页面3)双击安装包…

BEVFormer-accelerate:基于 EasyCV 加速 BEVFormer

导言 BEVFormer是一种纯视觉的自动驾驶感知算法,通过融合环视相机图像的空间和时序特征显式的生成具有强表征能力的BEV特征,并应用于下游3D检测、分割等任务,取得了SOTA的结果。我们在EasyCV开源框架(https://github.com/alibaba…

照片调色JixiPix Hand Tint Pro

JixiPix Hand Tint Pro带有专业分层系统的简单工作流程具有色调,色调,颜色,乘法,柔和涂料或可以逐层更改的涂料的模式,以及功能强大的选色工具,可在隔离区域内保持刷涂,以实现快速着色和准确性。…

Linux环境下多线程C/C++程序的内存问题诊断

目录说明常见的内存错误举例常见的内存访问错误有以下几种:内存问题定位步骤野指针内存释放后使用(UaF,Use after Free)内存问题检查工具常见的内存问题检查工具Valgrindgcc 命令行参数 -fsanitizeaddress -fno-omit-frame-pointe…

Prim算法

应用场景 1.如何修路才能保证修路的总路程最短? 特点: 1.将所有节点全部连通,并且边上的权总和最小——>最小生成树 2.N个顶点,有N-1条边 Prim算法图解分析 简而言之,就是先确定顶点A,然后寻找没有遍…

代码随想录训练营第52天|LeetCode 300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

参考 代码随想录 题目一:LeetCode 300.最长递增子序列 确定dp数组下标及其含义 dp[i]:在nums数组中,在下标0~i元素(包含i)的基础上,以nums[i]作为子序列的最后一个元素,组成的最长严格递增子序…

0126 搜索与回溯算法 Day15

剑指 Offer 34. 二叉树中和为某一值的路径 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1: 输入:root [5,4,8,11,null,13,…

cuda学习笔记4——cuda 核函数

cuda学习笔记4——cuda 核函数一、CUDA规范二、核函数内部线程的使用2.1 如何启动核函数demo 1:起16个线程来计算,四个线程块,每个块内四个线程例子demo2核函数是指在GPU端运行的代码,核函数内部主要干了什么?简而言之…

一个《跳动的爱心》代码,纯HTML+JS,双击直接运行

HTMLJS实现的一个跳动的爱心。集合了web动画库GSAP JS、OBJ 文件加载器OBJLoader、WebGL第三方库Three.js等。效果非常棒! 目录实际效果:目录结构:HTML代码CSS代码js代码:简单的修改完整文件下载实际效果: 由于是纯前端…

学会IDEA这些断点操作,生产问题解决的越来越快了

文章目录IDEA断点高级用法1、断点类型1)行断点(line breakpoints)2)字段断点(field breakpoints)3)方法断点(method breakpoints)1> 加载类名上的断点2> 正常方法断…

xss-labs(WriteUp)

xss-labs 先讲讲什么是跨站脚本攻击XSS(Cross Site Scripting) XSS原理 本质上是针对html的一种注入攻击,没有遵循数据与代码分离的原则,把用户输入的数据当作代码来执行 xss跨站脚本攻击是指恶意攻击者往Web页面里插入恶意脚本代码(包括当…

redis之codis和redis cluster对比

写在前面 codis和Redis cluster 都是Redis的集群方案,本文就一起来看下。 1:codis的组件和架构 codis的组件有4个,如下: codis server:基于redis进行了二次开发的组件,负责数据的读写 codis proxy&…

Halcon图像拼接

图像拼接在实际的应用场景很广,比如无人机航拍,遥感图像等等,图像拼接是进一步做图像理解基础步骤,拼接效果的好坏直接影响接下来的工作,所以一个好的图像拼接算法非常重要。 如按下图是将两张楼房图片拼接成一个图像。…

QT 学习笔记(九)

文章目录一、事件的接收和忽略1. 准备工作2. 接收和忽略二、event() 函数1. 简介2. 实例演示3. 总结三、事件过滤器四、总结(细看)1. 知识点汇总2. QT 的事件处理五、事件、事件的接收和忽略、event() 函数和事件过滤器代码1. 主窗口头文件 mywidget.h2.…

英语文本转语音软件哪个好?分享三个新手也能学会的工具

大家平时都是怎么学习英语的呢?课上老师让我们熟悉单词意思、巩固语法、多练阅读理解;其实通过练习听力来加强语感也很重要。很多小伙伴的阅读理解很好,但是听力却跟不上。这里教大家一个小技巧,就是在做阅读理解的时候&#xff0…

第十章TomCat详解

文章目录Tomcat的部署和启动Tomcat扮演的角色①对外:Web服务器②对内:Servlet容器深入理解为什么需要TomCat从目的开始出发遇到的问题总过程部署前提解压TomCat的目录文件启动Tomcat并访问首页如何部署一个项目访问对应的web资源专业版IDEA创建一个JavaW…

力扣(718.1143)补9.12

718.最长重复子数组 这题真的想不到。 看图的话会好懂很多。 class Solution { public int findLength(int[] nums1, int[] nums2) { int nnums1.length; int n2nums2.length; int[][] dpnew int[n1][n21]; int result0; for(int…