如果我是核酸系统架构师,我会这么用MQ。。。

news2024/11/24 18:33:45
V-xin:ruyuan0330 获得600+页原创精品文章汇总PDF

目录

  • 一、前情提示
  • 二、保证投递消息不丢失的confirm机制
  • 三、confirm机制的代码实现
  • 四、confirm机制投递消息的高延迟性
  • 五、高并发下如何投递消息才能不丢失
  • 六、消息中间件全链路100%数据不丢失能做到吗?

一、前情提示

上篇文章:《选Redis做MQ的人,是脑子里缺根弦儿吗?》,我们分析了RabbitMQ开启手动ack机制保证消费端数据不丢失的时候,prefetch机制对消费者的吞吐量以及内存消耗的影响。

通过分析,我们知道了prefetch过大容易导致内存溢出,prefetch过小又会导致消费吞吐量过低,所以在实际项目中需要慎重测试和设置。

这篇文章,我们转移到消息中间件的生产端,一起来看看如何保证投递到MQ的数据不丢失。

如果投递出去的消息在网络传输过程中丢失,或者在RabbitMQ的内存中还没写入磁盘的时候宕机,都会导致生产端投递到MQ的数据丢失。

而且丢失之后,生产端自己还感知不到,同时还没办法来补救。

下面的图就展示了这个问题。

在这里插入图片描述

所以本文呢,我们就来逐步分析一下。


二、保证投递消息不丢失的confirm机制

其实要解决这个问题,相信大家看过之前的消费端ack机制之后,也都猜到了。

很简单,就是生产端(比如上图的订单服务)首先需要开启一个confirm模式,接着投递到MQ的消息,如果MQ一旦将消息持久化到磁盘之后,必须也要回传一个confirm消息给生产端。

这样的话,如果生产端的服务接收到了这个confirm消息,就知道是已经持久化到磁盘了。

否则如果没有接收到confirm消息,那么就说明这条消息半路可能丢失了,此时你就可以重新投递消息到MQ去,确保消息不要丢失。

而且一旦你开启了confirm模式之后,每次消息投递也同样是有一个delivery tag的,也是起到唯一标识一次消息投递的作用。


这样,MQ回传ack给生产端的时候,会带上这个delivery tag。你就知道具体对应着哪一次消息投递了,可以删除这条消息。

此外,如果RabbitMQ接收到一条消息之后,结果内部出错发现无法处理这条消息,那么他会回传一个nack消息给生产端。此时你就会感知到这条消息可能处理有问题,你可以选择重新再次投递这条消息到MQ去。

或者另一种情况,如果某条消息很长时间都没给你回传ack/nack,那可能是极端意外情况发生了,数据也丢了,你也可以自己重新投递消息到MQ去。

通过这套confirm机制,就可以实现生产端投递消息不会丢失的效果。大家来看看下面的图,一起来感受一下。

在这里插入图片描述

三、confirm机制的代码实现

下面,我们再来看看confirm机制的代码实现:

在这里插入图片描述

四、confirm机制投递消息的高延迟性

这里有一个很关键的点,就是一旦启用了confirm机制投递消息到MQ之后,MQ是不保证什么时候会给你一个ack或者nack的。

因为RabbitMQ自己内部将消息持久化到磁盘,本身就是通过异步批量的方式来进行的。

正常情况下,你投递到RabbitMQ的消息都会先驻留在内存里,然后过了几百毫秒的延迟时间之后,再一次性批量把多条消息持久化到磁盘里去。

这样做,是为了兼顾高并发写入的吞吐量和性能的,因为要是你来一条消息就写一次磁盘,那么性能会很差,每次写磁盘都是一次fsync强制刷入磁盘的操作,是很耗时的。

所以正是因为这个原因,你打开了confirm模式之后,很可能你投递出去一条消息,要间隔几百毫秒之后,MQ才会把消息写入磁盘,接着你才会收到MQ回传过来的ack消息,这个就是所谓confirm机制投递消息的高延迟性

大家看看下面的图,一起来感受一下。

在这里插入图片描述

五、高并发下如何投递消息才能不丢失

大家可以考虑一下,在生产端高并发写入MQ的场景下,你会面临两个问题:

  • 1、你每次写一条消息到MQ,为了等待这条消息的ack,必须把消息保存到一个存储里。

并且这个存储不建议是内存,因为高并发下消息是很多的,每秒可能都几千甚至上万的消息投递出去,消息的ack要等几百毫秒的话,放内存可能有内存溢出的风险。

  • 2、绝对不能以同步写消息 + 等待ack的方式来投递,那样会导致每次投递一个消息都同步阻塞等待几百毫秒,会导致投递性能和吞吐量大幅度下降。

针对这两个问题,相对应的方案其实也呼之欲出了。


首先,用来临时存放未ack消息的存储需要承载高并发写入,而且我们不需要什么复杂的运算操作,这种存储首选绝对不是MySQL之类的数据库,而建议采用kv存储。kv存储承载高并发能力极强,而且kv操作性能很高。

其次,投递消息之后等待ack的过程必须是异步的,也就是类似上面那样的代码,已经给出了一个初步的异步回调的方式。

消息投递出去之后,这个投递的线程其实就可以返回了,至于每个消息的异步回调,是通过在channel注册一个confirm监听器实现的。

收到一个消息ack之后,就从kv存储中删除这条临时消息;收到一个消息nack之后,就从kv存储提取这条消息然后重新投递一次即可;也可以自己对kv存储里的消息做监控,如果超过一定时长没收到ack,就主动重发消息。

大家看看下面的图,一起来体会一下:
在这里插入图片描述

六、消息中间件全链路100%数据不丢失能做到吗?

到此为止,我们已经把生产端和消费端如何保证消息不丢失的相关技术方案结合RabbitMQ这种中间件都给大家分析过了。

其实,架构思想是通用的, 无论你用的是哪一种MQ中间件,他们提供的功能是不太一样的,但是你都需要考虑如下几点:

  1. 生产端如何保证投递出去的消息不丢失:消息在半路丢失,或者在MQ内存中宕机导致丢失,此时你如何基于MQ的功能保证消息不要丢失?
  2. MQ自身如何保证消息不丢失:起码需要让MQ对消息是有持久化到磁盘这个机制。
  3. 消费端如何保证消费到的消息不丢失:如果你处理到一半消费端宕机,导致消息丢失,此时怎么办?

目前来说,我们初步的借着RabbitMQ举例,已经把从前到后一整套技术方案的原理、设计和实现都给大家分析了一遍了。


但是此时真的能做到100%数据不丢失吗?恐怕未必,大家再考虑一下个特殊的场景。

生产端投递了消息到MQ,而且持久化到磁盘并且回传ack给生产端了。

但是此时MQ还没投递消息给消费端,结果MQ部署的机器突然宕机,而且因为未知的原因磁盘损坏了,直接在物理层面导致MQ持久化到磁盘的数据找不回来了。

这个大家千万别以为是开玩笑的,大家如果留意留意行业新闻,这种磁盘损坏导致数据丢失的是真的有的。

那么此时即使你把MQ重启了,磁盘上的数据也丢失了,数据是不是还是丢失了?

你说,我可以用MQ的集群机制啊,给一个数据做多个副本,比如后面我们就会给大家分析RabbitMQ的镜像集群机制,确实可以做到数据多副本。

但是即使数据多副本,一定可以做到100%数据不丢失


比如说你的机房突然遇到地震,结果机房里的机器全部没了,数据是不是还是全丢了?

说这个,并不是说要抬杠。而是告诉大家,技术这个东西,100%都是理论上的期望。

应该说,我们凡事都朝着100%去做,但是理论上是不可能完全做到100%保证的,可能就是做到99.9999%的可能性数据不丢失,但是还是有千万分之一的概率会丢失。

当然,从实际的情况来说,能做到这种地步,其实基本上已经基本数据不会丢失了。

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

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

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

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

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

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

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

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

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

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

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

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

相关文章

医学图像包——DCMTK、VTK、ITK、RTK、SimpleITK

1.ITK-医学图像处理软件包 ITK( Insight Segmentation and Registration Toolkit)是美国国家卫生院下属的国立医学图书馆开发的一款医学图像处理软件包,是一个开源的、跨平台的影像分析扩展软件工具。 ITK的开发过程中采用了先进的多模态数…

VAE详解及PyTorch代码

三大有名的生成模型VAE、GAN以及Diffusion Model 其余两篇 看了网上的一些博客,大多都写到了重点,也就是后面的公式推导部分,可是大部分只有推导过程,很少有讲明白为什么要这么假设,我看的时候内心不断有个疑问&…

这篇文章详细介绍动态内存管理 ,让你醍醐灌顶【c语言】

文章目录动态内存函数mallocfreecallocrealloc常见的动态内存错误对NULL指针的解引用操作对动态开辟空间的越界访问对非动态开辟内存使用free释放使用free释放一块动态开辟内存的一部分对同一块动态内存多次释放动态开辟内存忘记释放(内存泄漏)练习柔性数…

物联网终端的信息保护

针对漏洞的恶意行为分析 我们共捕获到 4 种针对 UPnP 漏洞的利用行为 1,如表 4.7 所示。从中可以看出,这些漏洞均为远程 命令执行类漏洞。另外我们也发现,当漏洞出现在特定端口时,攻击者一般不会经过 UPnP 的发现阶段&#xff0c…

Moran指数分析

Moran指数分析 Moran指数(莫兰指数)是研究空间关系的一种相关系数值,比如研究中国31省市GDP之间是否具有空间相关关系。Moran指数通常分为两种,分别是全局Moran指数和local局部Moran指数。全局Moran指数用于分析整体上是否存在空…

概率分布到底有什么用?

1.1 要概率分布有什么用? 个人理解:每种概率分布对应描述了某种特定事件发生的规律,像是一个模板,只要某种事件符合该分布的要求,那么就可以用对应的概率分布计算此事件的概率 1.2 为什么非要确定一个分布?…

计算机组成原理复习题

一、选择题 一个节拍信号的宽度是指______。 A. 指令周期 B. 存储周期 C. 机器周期 D. 时钟周期 我的答案: D正确答案: D 3.3分 2. (单选题) 中断向量地址是______。 A. 子程序入口地址 B. 中断服务子程序出口地址 C. 中断返回地址 D. 中断服务子程序入口地址 我的答案: D正…

SpringCloudAlibaba、SpringCloud版本和SpringBoot版本适配

本文继SpringCloud版本和SpringBoot版本适配后,加入SpringCloudAlibaba组件版本适配! 官网链接:https://github.com/alibaba/spring-cloud-alibaba/wiki/

MySQL基本用法

一、数据库的基本操作: 1、启动数据库:net start mysql; 2、进入数据库:mysql -h localhost -u root -p; 3、关闭数据库服务:net stop mysql; 4、查看数据库:show databases; 5、新建数据库:create databa…

[vue element-ui]JAVA POST请求

01.前端 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><script type"text/javascript" src"js/jquery-3.4.1.min.js"></script><script type"text/javascript&qu…

Raft论文翻译(5.4.2)——安全性-提交之前term的日志entry

5.4.2 Committing entries from previous terms 提交之前term的日志entry As described in Section 5.3, a leader knows that an entry from its current term is committed once that entry is stored on a majority of the servers. If a leader crashes before committin…

linux 分析启动时服务时间消耗

工具systemd-analyze systemd-analyze是一个分析启动性能的工具&#xff0c;用于分析启动时服务时间消耗。 1 systemd-analyze使用 1.1 查看启动耗时 rootloongson-pc:/# systemd-analyze 1.2 查看每个服务的启动耗时 rootloongson-pc:/# systemd-analyze blame 1.3 显…

Docker安装配置运行Redis

本文前提是基于已安装Docker容器引擎。Ubuntu安装docker容器引擎_流沙QS的博客-CSDN博客 1.拉取redis镜像 sudo docker pull redis 2.创建文件挂载目录并进入到创建目录&#xff0c;下载官方的redis.conf配置文件 mkdir -p /home/geng/soft/redis wget http://download.re…

如何在每次辩论中都取得胜利,捍卫自己的权力-----苏格拉底产婆术

文章目录苏格拉底的产婆术四步法是&#xff1a;产婆术&#xff08;art of midwifery&#xff09;苏格拉底&#xff1a;认识你自己&#x1f338;I could be bounded in a nutshell and count myself a king of infinite space. 特别鸣谢&#xff1a;木芯工作室 、Ivan from Rus…

2022年度《中国数字安全能力图谱(精选版)》发布,中睿天下实力入选

近日&#xff0c;国内数字安全领域中立的第三方调研机构数世咨询正式发布《2022年度中国数字安全能力图谱&#xff08;精选版&#xff09;》&#xff08;以下简称能力图谱&#xff09;&#xff0c;中睿天下凭借领先的技术创新实力&#xff0c;成功入选上榜高级威胁防御能力者及…

照片如何加滤镜?一步一步教会你给图片加上滤镜

我们在外出游玩的时候&#xff0c;常常会拍摄一些好看的风景照或者是美食照&#xff0c;有时我们还会将这些不错的照片分享在社交平台上&#xff0c;相信这个时候你们在分享照片之前&#xff0c;都会先给照片添加滤镜&#xff0c;因为一个好的滤镜&#xff0c;不仅能够美化照片…

7的2022年终总结

7&的2022年终总结 文章目录7&的2022年终总结1、前言2、技术3、生活4、展望未来1、前言 2022年&#xff0c;终究是不平凡的一年。 2022年2月4日&#xff0c;中国农历大年初四&#xff0c;这一天&#xff0c;北京冬奥会将拉开大幕。 2022年3月份&#xff0c;疫情还未结束…

Linux小白入门经验

雄关漫道真如铁&#xff0c;而今迈步从头越。我们在单位工作的人都有一个梦想&#xff0c;那就是搞定所有的计算机难题&#xff0c;帮助公司完成更多的电脑维修、软件开发以及系统监测。随着互联网的深入发展&#xff0c;我们都在很努力的学习各种程序和系统&#xff0c;希望能…

20个python编码小技巧-推导式、翻转、排序、迭代器等等

本文分享一些 Python 技巧&#xff0c;它可以让你的代码更简洁、更高效。 1.列表推导式 li [x for x in range(10) if x % 2 0] print(li) # [0, 2, 4, 6, 8]li [i*2 if i%20 else i*3 for i in range(10)] print(li) # [0, 3, 4, 9, 8, 15, 12, 21, 16, 27]# 应用&#xf…

flutter 并不完美的登录完美验证功能

flutter 并不完美的登录完美验证功能前言一、文本输入功能二、验证提示功能三、业务部分总结前言 在一个APP 中&#xff0c;登录页面做为门户&#xff0c;很多时候&#xff0c;我们都需要写一个完善的登录验证页面&#xff0c;本篇文章将记录如何去封装一个并不算完美的登录验…