延时消息+递归导致重复消费爆炸问题

背景

        公司所用消息队列为RoucketMQ,版本为4.x。最近公司有业务需要,将某个处理延迟到第二天的白天再进行。由于4.x版本队列,默认延时时间是按等级来延时的,默认有18个等级,如下图:

        默认的延时等级,无法满足延时任意时间的需要,所以现有的实现方式,是采用:延时队列+时间轮。延时队列可以延时指定等级的时间,当剩余时间小于1min时,再封装成定时任务,投递给netty中的时间轮来处理。然而当延时时间超过2H时,单次的延时队列已无法满足(默认最高2H),此时现有方案是递归的方式,继续延迟(当然也可以增加延时等级,减少递归次数)。实现方案如下图(以延时1.5H为例):

        在已有的延时业务下,通常都是短时间延迟,2H之内,所以以上方案未出现较大问题。

发现问题

        最近新增了业务需求,要求延时到第二天,例如延时20H,继续使用了上述方案,但后继续通过MQ的Console发现,延时队列的消息积压非常严重,数量远超出业务数量。然后开始通过ELK查看消息的消费日志,发现UUID标识的唯一消息,重复消费较严重,如下图:

排查问题

        图中只是重复消费的一部分,实际重复消费很严重,单条消息被重复消费了上万次(还好是在测试环境,生产不敢想象【狗头】)。

        然后,就准备从重复消费入手,未何会重复消费这么多次呢,查看mq的消费重试次数

RetryTimesSendFailed=2,意思是第一次消费未返回成功的话(未消费成功的原因有多种,可以另外查阅),会再进行两次重试,那就是会进行一次消费最多消费3次。

        通过上述延时方案图发现,当延时2H后,剩余时间仍超过60S时,会递归再进行延时2H,以此类推,那么问题就来了:如果以此延时重复消费3次,那么递归一次,原本重复的每次再重复3次,就是重复3*3=9次;第二次递归,就是重复3*3*3=27次;第三次递归就是3*3*3*3=81次……。随着递归次数增加,重复消费次数指数级增长,想想就阔怕。

        通过上图的日志图,每个时间点的重复消费次数:1、3、9、27……也验证了上述的推理。

解决问题

        那既然找到了上述重复消费的原因,我们也可以针对性的采取一些措施来应对,以下是想到一些初步举措,后续可能结合具体情况再做优化; 

  1. 如果消息消费的可靠性不是要求特别高,或者有其他补偿机制,最快速的方式,直接配置RetryTimesSendFailed=0,这样就没有重试,因而也就没有重复消费,即使递归延时也不影响。
  2. 通常情况下,可能不方便关闭重试,那就可以在消费时,进行幂等控制。这样即使进行重复消费,也只有一条消息正常消费执行。
  3. 如果只是采取第2条的话,由于递归次数没变,可能还是会存在一定数量的重复消费。我们可以扩展MQ默认的延时等级,比如增加5H/10H/20H/40H的延时等级,这样可以减少递归延时的重试次数,进而减少重复消费次数。
  4. 如果运维层面支持的话,我们也可以将RocketMQ升级为5.x版本,这个版本是支持任务时间的延时的,所以就不用自行扩展通过递归的方式来延时了。

思考总结

        通过上述分析,这次出现的重复消费的问题,还是挺严重,但幸好还是在测试环境,发生在了生产,估计都得提桶跑路了。通过上述问题排查,也总结了一些日常要注意的地方:

  1. 使用消息队列时,考虑可能出现的常见问题:重复消费,消息积压、消息丢失等;充分测试确保不会出现上述问题;
  2. 慎重使用递归、死循环;我们相信正常流程执行的话,递归和死循环是不会有大问题的;但根据墨菲定律,虽然意外情况概率小,但仍可能出现。所以使用递归、死循环时,一定要慎重,考虑各种意外场景,且考虑中断策略。
  3. 测试要覆盖实际业务场景,像上述问题,如果测试为了快速验证测试结果,只是延时了几分钟,那么递归延迟就不会触发,问题也不会再测试环境暴露。所以测试要全面,保证覆盖实际的业务场景
  4. 技术层面,我们需要重复理解学习所用的技术栈,如果不能知其所以然,那么一些容易出问题的地方,可能就会被我们所忽略,进而导致更大的问题。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

eve-ng山石网科HillStone镜像部署

HillStone 部署 author:leadlife data:2023/12/4 mains:EVE-ng HillStone 镜像部署 - use hillstone-sg6000 default:hillstone/hillstone 传输 scp hillstone-sg6000.zip root192.168.3.130:/opt/unetlab/addons/qemu/部署 cd …

12.4每日一题(备战蓝桥杯顺序结构程序设计)

12.4每日一题(备战蓝桥杯顺序结构程序设计) 题目1000: 【入门】AB Problem题目描述输入输出样例输入样例输出来源/分类 题解 1000: 【入门】AB Problem题目 2124: 计算(ab)c的值题目描述输入输出样例输入样例输出来源/分类 题解 2124: 计算(ab)c的值题目…

C语言-字符串操作函数-附加使用方式

文章目录 前言字符串复制-strcpy字符串复制(按照位数)-strncpy字符串比较-strcmp字符串比较(按照位数)-strncmp不区分大小写的字符串比较-strcasecmp不区分大小写的比较(前n位)-strncasecmp字符串按照格式写入-sprintf字符串按照格式和个数写入-snprintf…

使用贝叶斯网络检测因果关系,提升模型效果更科学(附Python代码)

虽然机器学习技术可以实现良好的性能,但提取与目标变量的因果关系并不直观。换句话说,就是:哪些变量对目标变量有直接的因果影响? 机器学习的一个分支是贝叶斯概率图模型(Bayesian probabilistic graphical models),也…

SpringCloud网关介绍

一、Gateway简介 1、官网 上一代zuul 1.X:https://github.com/Netflix/zuul/wiki 当前gateway:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/ 2、是什么 SpringCloud Gateway是SpringCloud的一个全…

2023 CCF中国软件大会(CCF ChinaSoft)“软件工程教育”论坛 成功召开

2023年12月1日,2023年度CCF中国软件大会“软件工程教育”论坛成功召开。 ✦ 自去年来大模型技术的出现以及在各个领域的应用,对相关的学科和行业产生了深刻的影响。软件工程首当其冲,以ChatGpt和CopilotX等为代表的智能化开发工具可以帮助软…

Spring Boot 3 集成 Druid 连接池详解

在现代的Java应用中,使用一个高效可靠的数据源是至关重要的。Druid连接池作为一款强大的数据库连接池,提供了丰富的监控和管理功能,成为很多Java项目的首选。本文将详细介绍如何在Spring Boot 3项目中配置数据源,集成Druid连接池&…

我对迁移学习的一点理解(系列2)

文章目录 我对迁移学习的一点理解 我对迁移学习的一点理解 源域和目标域是相对的概念,指的是在迁移学习任务中涉及到的两个不同的数据集或领域。 源域(Source Domain)通常指的是已经进行过训练和学习的数据集,它被用来提取特征、…

2023-12-09 LeetCode每日一题(下一个更大的数值平衡数)

2023-12-09每日一题 一、题目编号 2048. 下一个更大的数值平衡数二、题目链接 点击跳转到题目位置 三、题目描述 如果整数 x 满足:对于每个数位 d ,这个数位 恰好 在 x 中出现 d 次。那么整数 x 就是一个 数值平衡数 。 给你一个整数 n &#xff0…

Temu卖家如何获取流量?Temu新手卖家流量来源哪里?——站斧浏览器

流量对于每个平台来说都是很重要的,那么Temu卖家如何获取流量?流量来源哪里? Temu卖家如何获取流量? 1、优化产品标题和描述:在Temu平台上,买家通常通过搜索关键词来寻找他们感兴趣的产品。因此&#xff…

Axios 拦截器实战教程:简单易懂

Axios 提供了一种称为 “拦截器(interceptors)” 的功能,使我们能够在请求或响应被发送或处理之前对它们进行全局处理。拦截器为我们提供了一种简洁而强大的方式来转换请求和响应、进行错误处理、添加认证信息等操作。在本文中,我…

P10 Linux进程编程 fork创建子进程

目录 前言 01 fork()创建子进程 示例 1使用 fork()创建子进程。 02 fork创建新进程时发生了什么事? 2.1 父、子进程中对应的文件描述符指向了相同的文件表 前言 🎬 个人主页:ChenPi 🐻推荐专栏1: 《Linux C应用编程&#xf…

[Linux] yum安装分布式LNMP架构

1. 在一台主机安装nginx(192.168.136.120) 1.1 搭建nginx相关的yum源 cd /yum.repos.d mkdir bak mv *.repo bak vim /etc/yum.repos.d/nginx.repo [nginx-stable] namenginx stable repo baseurlhttp://nginx.org/packages/centos/7/$basearch/ gpgche…

题解:CF1902A. Binary Imbalance

题解:CF1902A. Binary Imbalance 先给个题目链接。 题目翻译(由“CodeForces Better!”和“DeepL 翻译”提供): 我们知道,如果初始字符串中“0”的个数就大于“1”的个数,答案肯定是YES&…

【二分答案法】Leetcode相关题目解析

题目:162. 寻找峰值 - 力扣(LeetCode) 题目描述: 题目分析: (1)据题知,索引-1、索引n(n为数组长度)处的元素都默认为无穷小,我们可以在一开始特判…

软件设计师——操作系统(一)

📑前言 本文主要是【操作系统】——软件设计师——操作系统的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 &#x1f304…

鸿蒙开发组件之ForEach列表

一、ForEach函数 ForEach函数是一个迭代函数,需要传递两个必须参数和一个可选参数。主要通过迭代来获取参数arr中的数据不断的生成单个Item来生成鸿蒙中的列表样式 二、先创建单个的Item的UI 通过嵌套Row与Column来实现单个Item的UI。例如图中没有折扣的可以看成一…

Pandas中DataFrame对象的创建与常用属性方法(第2讲)

Pandas中DataFrame对象的创建与常用属性方法(第2讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔…

【Docker】swarm stack部署多service应用

前面我们已经学习过了Docker Compose,它可以用来进行一个完整的应用程序相互依赖的多个容器的编排的,但是缺点是只能在单机模式使用,不能在分布式多机器上使用;前面我们也学习了Docker swarm,它可以将单个服务部署为多…

鸿蒙生态开发就业前景到底好不好

鸿蒙生态开发是指基于华为自主研发的操作系统鸿蒙(HarmonyOS)进行应用程序开发和生态建设。目前,鸿蒙生态开发的前景非常好,原因如下:做鸿蒙应用开发到底学习些啥? (qq.com) 1:政府支持&#x…
最新文章