深入浅出消息队列----【如何保证消息不重复?】

news2024/11/15 18:03:52

深入浅出消息队列----【如何保证消息不重复?】

  • 消息一定会重复
  • 消息幂等消费
    • 改造业务符合天然幂等写法
    • 数据库唯一索引
    • redis 唯一判断

本文仅是文章笔记,整理了原文章中重要的知识点、记录了个人的看法
文章来源:编程导航-鱼皮【yes哥深入浅出消息队列专栏】

消息一定会重复

发送消息的流程:

请添加图片描述

生产者发送消息给 Broker 后,需要等待 Broker 响应的 ack 才能确保消息已经被 Broker 存储了,以这种请求-应答的模式来确保消息一定被接收到,不会丢失。

那么假设 Broker 确实已经收到了这条消息并成功存储了,但返回给生产者 ack 的时候因为网络原因,生产者并没有收到这条消息的 ack,那么为了保证消息不会丢失,生产者只能再次发生这次消息。

在这种情况下,同一条消息被发送了两次,Broker 上就存在了两条一样的消息。

看到这有同学回想,既然为了保证消息不丢失,生产者没办法,只能多次发送同一条消息,那么就由 Broker 来过滤这些重复的消息吧!

理论上确实可以这样实现,但是实际应用上消息的体量都会比较大,Broker 本身的负载就不低,如果要加上去重功能,那么势必需要解析接收到的所有消息内容,然后进行对比,这会进一步加重 Broker 的负担,在高并发情况下还会大大降低性能。

从我们之前分析的 RocketMQ Broker 的存储流程来看,它并没有支持这个去重功能,包括是市面上别的消息队列中间件都不支持,因此想让 Broker 自动去重是没戏了。

所以,从发送流程来看,无法避免消息不重复发送,如果网络抖动 Broker 很可能会存储多条一模一样的消息。

从消费的流程来看,即使 Broker 实现了消息去重功能,也无法保证同一条消息一定只被消费者消费一次。

之前已经提到消费者是通过提交消费点位来跟 Broker 同步已经消费到的位置。

在集群模式下,消费点位是存储在 Broker 上的,并且是消费者在拉取消息的时候顺带把此时的消费点提交给 Broker。

假设消费者消费完消息后,立马挂了,此时的消息点位还没有提交到 Broker,然后发送对垒重平衡后,另一个消费者顶上了这个队列的消费,就产生了消息的重复消费。

所以不论从生成、存储、还是消费三个方向来看,都无法保证消息的不重复。

虽然消息无法保证不重复,但是我们可以保证它仅被幂等消费来达到和仅消费一次的效果

消息幂等消费

所谓的幂等其实是数学上的一个概念,f(f(x)) = f(x),对我们程序而言就是一个方法被同样的入参调用一次和多次产生的影响是一样的。

假设你的方法里面就是一条 update 语句:

update tableA set name = 'yes' where id = 1

像这样的逻辑,无论被执行多少次,和只执行一次达到的效果是一样的,这就是我们程序上的幂等。

因此,既然我们无法保证消息不重复,但是可以利用幂等来避免重复消费产生的影响

那如何保证消息的幂等消费呢?

改造业务符合天然幂等写法

在项目初期或者新功能刚开始设计的时候,就可以考虑幂等的设计来满足业务需求,好比我上面提到的那个 update 语句,利用天然的幂等写法来满足消息的幂等消费,这是最简单和自然的一种方式。

然后可以给 update 设置一些前置条件。

比如现在有个消费消息业务逻辑:给用户加积分,并且将订单的状态从待完成变成已完成。

首先我们要调整下执行的顺序,不是先加积分,而是先改变订单的状态,执行:

update order set status = 1 where orderNO = 123 and status = 0;

添加一个 status = 0 的判断,如果消息已经被消费过,那么 orderNo 123 这个订单的 status 肯定已经是 1 了。

这样一来这个 update 执行之后影响的行数是 0,通过这个我们就能确定消息是否重复消费。

如果是重复消费,流程直接终止,这样后面给用户加积分这种不好利用 update 实现幂等操作的业务,利用前置其它业务处理也能实现幂等,重复消费也不会使得用户的积分被多加。

在业务上幂等改造就需要抓住这些点,将一些容易完成幂等改造的业务前置处理,并添加一些约束条件,提前终止重复消费,使得完整的大业务都实现了幂等。

数据库唯一索引

但是往往很多需求不是初期就有的,而是后面迭代的,此时整个业务流程基本上已经定型了,业务逻辑可能已经很复杂,不太好改造出上述 update 这样的语句来满足当下的业务需求。

此时可以利用数据库的唯一索引约束来保证消费的幂等消息。

例如可以给消息价格事务 ID,这个事务 ID 是全局唯一的,数据库表记录给这个事务 ID 添加唯一索引,当第一次处理完成这条消息的时候,同时在数据库中存储这条消息的处理记录,如果后面有重复消息过来,那么插入一定是会抛错的,这样一来就能避免消息的重复消费实现消费幂等。

具体操作起来大致两个方向:第一个方向时利用当前的已有的字段来作为唯一索引,比如订单的处理,那么订单的订单号肯定是唯一的,此时不需要再额外添加一个事务 ID 的字段。

如果没有合适的已有字段,那么就扩展一个事务 ID 字段来满足要求。

如果当下的业务表结构或者处理流程不方便扩展新的字段,那么消费端可以添加一张流水表来存储新的事务 ID 字段,将这个流水表的事务和业务处理放在一个事务中,这样就能保证业务事务执行成功后流水表一定添加上了,这样通过流水表就能实现消息的幂等。

请添加图片描述

redis 唯一判断

同样 redis 也能实现幂等的功能,相比数据库的唯一索引需要改表结构,或者新加一张流水表,redis 更加简单,利用 SETEX 这个命令就能实现幂等消费。

同样也是用全局唯一值来标记这条消息,例如订单号或者定义的事务 ID,每次在业务逻辑执行之前先利用 SETNX 来判断下,如果已经插入就直接返回,反之正常执行业务逻辑。

但是这里有个问题,如果唯一值插入 redis 后,消费者直接宕机了,业务逻辑并没有执行成功,那么即使由另一个消费者顶上消费到这条消息,由于 redis 还存储着这个唯一值,会使得这条消息被跳过,这样这条消息就跟丢了是一样的。

所以在异常情况下,这个方案会有这个问题,需要注意!

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

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

相关文章

从零开始的大模型训练教程

近年来,随着人工智能技术的迅猛发展,大模型(Large Models)成为了业界关注的焦点。这些模型,尤其是那些基于Transformer架构的自然语言处理模型,如GPT系列、BERT等,在各种任务上取得了前所未有的…

git add . 警告

这些警告是因为 Git 检测到你的文件使用了不同的换行符(LF 或 CRLF),并提示在下次 Git 操作中将会统一换行符为 CRLF。这通常发生在跨平台协作时,例如在 Windows 环境下编辑的文件可能使用 CRLF,而在类 Unix 环境&…

数据结构:基于顺序表实现通讯录系统(含源码)

目录 一、前言 二、各个功能的实现 2.1 初始化通讯录 2.2 添加通讯录数据 2.3 查找通讯录数据 2.4 删除通讯录数据 2.5 修改通讯录数据 2.6 展示通讯录数据​编辑 2.7 销毁通讯录数据 三、添加菜单和测试 四、完整源码 sxb.h sxb.c contact.h contact.c test.c 一、前…

ROS智能移动机器人实训

0.前言 1.任务 1.1.任务实训任务 1.使用/voice_aiui等语音服务完成基本的语音聊天(需唤醒词“元宝”)。 2.语音多点导航 3.语音单点导航 1.2.智能机器人仿真任务 1.3.智能机器人实物操作任务 2.目的 3.使用环境 4.综合项目实验 任务实训 问题 解决办法…

LinuxIO之文件系统的实现

Ext2/3/4 的layout文件系统的一致性: append一个文件的全流程掉电与文件系统的一致性fsck文件系统的日志ext4 mount选项文件系统的debug和dumpCopy On Write 文件系统: btrfs 预备知识:数据库里的transaction(事务)有什么特性? …

前端高薪岗位之大模型端上部署及训练

自2022年ChatGPT发布以来,以大模型为依托的AIGC相关的应用产品,比如ChatGPT、Midjourney、Stable Diffusion等,在社交网站的讨论热度持续攀升,引发了较大范围的好奇与关注。 目前,国内外各个科技大厂在大模型的端侧部…

手机k歌麦克风哪种好,口碑最好的k歌麦克风是哪款,麦克风推荐

​当我们谈论到演讲、表演或者录制视频时,一个高质量的无线麦克风能够使得整个体验提升至一个全新的水平。它不仅能够保证声音的清晰度和真实度,还能够让使用者在演讲或者表演时更加自信和舒适。基于对市场的深入研究和用户体验的考量,我挑选…

Langchain-Chatchat+Xinference集成部署

Langchain-ChatchatXinference集成部署 安装环境: 系统:Anolis OS 8.9 python版本:Python 3.9.19 Langchain-Chatchat版本:0.3.1.3 Xinference版本:v0.13.3 模型选择(下载时需要科学上网)&#…

一些常见的中间件漏洞

Tomcat 之CVE-2017-12615 靶场搭建使用vulhub-master/tomcat/CVE-2017-12615 第一步、访问网站 第二步、首页抓包改为put方式提交 网上找一个jsp的一句话木马 使用webshell工具链接即可 Tomcat 之tomcat8 vulhub-master/tomcat/tomcat8 继续访问页面 这次我们点击登录&…

ES6中的Promise、async、await,超详细讲解!

Promise是es6引入的异步编程新解决方案,Promise实例和原型上有reject、resolve、all、then、catch、finally等多个方法,语法上promise就是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果,本篇文章主要介绍了ES6中的P…

spring原理(第十天)

jdk 和 cglib 在 Spring 中的统一 Spring 中对切点、通知、切面的抽象如下 切点:接口 Pointcut,典型实现 AspectJExpressionPointcut 通知:典型接口为 MethodInterceptor 代表环绕通知 切面:Advisor,包含一个 Advic…

政务服务技能竞赛规则流程方案

此次政务服务技能竞赛以“强服务、优素质、促提升、共发展”为目标,通过以赛代练、以赛促建、比学赶超、全面提升,激发各级政务服务工作人员学政策、钻业务、练技能的热情和积极性,全面推动行政效能提升与营商环境建设,铸造新时代…

pytorch和deep learning技巧和bug解决方法短篇收集

有一些几句话就可以说明白的观点或者解决的的问题,小虎单独收集到这里。 torch.hub.load how does it work 下载预训练模型再载入,用程序下载链接可能失效。 model torch.hub.load(ultralytics/yolov5, yolov5s)model torch.hub.load(ultralytics/y…

IROS2024 | DarkGS:学习神经照明和3D高斯重新照明,用于黑暗中机器人探索

DarkGS:学习神经照明和3D高斯重新照明,用于黑暗中机器人探索 论文标题:DarkGS: Learning Neural Illumination and 3D Gaussians Relighting for Robotic Exploration in the Dark 论文地址:https://arxiv.org/abs/2403.10814 研…

数据开发/数仓工程师上手指南(七)CDM-DWS层搭建规范及流程

前言 进入到了CMD公共数据层的结尾最后一层-DWS层了,该层基本就是直接与业务强关联,也就是说产品提出的需求,或是报表、用户画像统计好还是数据大屏都是在这一层给处理好数据,再放入ADS层,然后我们只需要在BI里面配备…

【数据结构】——堆的实现(赋源码)

堆的概念与结构 堆(Heap)是计算机科学中一类特殊的数据结构,是最高效的优先级队列。堆通常是一个可以被看作一棵完全二叉树的数组对象。 堆的性质: 堆中某个结点的值总是不大于或不小于其父结点的值; 堆总是一棵完全二叉树。 堆的物理结构本质上是顺序…

PDF怎么转Word?分享二个简单的方法

很多小伙伴在工作学习的时候,经常会遇到别人发来的PDF文件。PDF 文件用于查看资料非常方便,因为它们的布局稳定,在大多数设备上都可以显示相同的布局。 如果我们需要将其转换为Word,如何转换呢?许多人不知道如何转换。…

怎么录制视频?简单步骤教你如何录制高质量视频

视频是我们生活、工作和学校中不可或缺的一部分,但对于初学者来说,面对琳琅满目的录屏工具,往往感到无从下手,今天我们就给大家分享几种简单又高效的电脑录屏方法,让你轻松掌握高质量视频录制的技巧。 录制技巧1&#…

工厂人员定位系统原理

工厂人员定位系统是一种通过现代无线通讯技术和定位技术实现对工厂内人员位置进行实时监测的系统。其具体原理是通过安装在员工身上的定位标签产生无线电信号,并通过无线通讯网络传输给基站,再由基站将数据传输到服务器进行处理,最终在监控中…

《藏文驾考》App:支持藏汉双语切换的驾考题库,方便不熟汉语的藏族学员考驾照,中文藏文语音读题!

藏文驾考,是一款支持藏汉双语切换的驾照考试在线刷题学习软件。服务于涉藏地区的藏文驾驶理论考试,同步西藏、四川、青海、甘南等涉藏地区的驾考新规题库。提供科目一、科目四藏文交规理论学习,科目二、科目三视频技巧讲解。支持汉语、卫藏、…