聊一下订单超时自动关闭的几种方式以及使用场景

news2024/11/17 14:01:32

订单超时自动关闭的本质其实是一种延时的功能实现,具体实现方式有很多种,但是我们方式的选择是需要结合业务场景的,没有更好的方案,只有更适合的方案,所以我们必须要结合自己的实际业务,以及业务的后续发展,以及时间的紧迫程度进行选择。

在这里,我会将每一种方式的实现步骤,优缺点,以及适用场景都会给大家说清楚,供大家选择。

1. 消息队列模式实现

消息队列是一种解耦合、异步处理的方式,非常适合用于实现订单超时关闭功能。在订单创建时,向消息队列发送一个定时消息,消息的延时时间设置为订单的超时时间。如果订单在超时时间内未完成支付,消息队列将触发关闭订单的操作。

在这里插入图片描述

实现步骤:

  1. 在订单创建时,向消息队列发送一个定时消息,消息的延时时间设置为订单的超时时间。
  2. 消息队列在消息到期时触发关闭订单的操作。
  3. 关闭订单后,执行相应的后续处理逻辑,如释放库存、通知用户等。

优点:

  • 解耦合:订单创建和关闭操作通过消息队列进行解耦合,提高了系统的可扩展性和可靠性。
  • 异步处理:订单关闭操作在消息到期时异步执行,不会阻塞主业务逻辑。

缺点:

  1. 常用的消息中间件对延迟的时间是有一定规定的,比如RabbitMQ最大延迟时间是2的32次方毫秒,RocketMQ的消息延时只有特定的 18个级别,灵活度不够。
  2. 还有我们如果使用的是开源版本的RocketMQ,注意是没有删除延时消息的功能,因此需要对每条消息都做超时判断,增加了很多无效的数据处理。
  3. 强依赖消息中间件,所以我们需要保证MQ的稳定以及持续消费功能,防止消息丢失和积压问题。

2. Kafka的时间轮

这种方案也是比较优秀的,如果大家的项目中,采用的消息中间件是Kafka,又想利用中间件处理延迟队列的话,可以采用这种方式,我没有试过,但是大家可以看下这篇文章,感觉还是比较透彻的,后续我也会给大家专门做一个实践。
Kafka的时间轮实现延迟队列

3. 定时轮询模式

具体实现细节就是我们通过一些调度平台(XXL-Job,SchedulerX)来实现定时执行任务,任务就是去扫描所有到期的订单,然后执行关单动作。

在这里插入图片描述

优点:

  • 实现起来很容易,基于Timer、ScheduledThreadPoolExecutor、或者像xxl-job这类调度框架都能实现

缺点:

  1. 时间不精准。 一般定时任务基于固定的频率、按照时间定时执行的,那么就可能会发生很多订单已经到了超时时间,但是定时任务的调度时间还没到,那么就会导致这些订单的实际关闭时间要比应该关闭的时间晚一些。
  2. 无法处理大订单量。 定时任务的方式是会把本来比较分散的关闭时间集中到任务调度的那一段时间,如果订单量比较大的话,那么就可能导致任务执行时间很长,整个任务的时间越长,订单被扫描到时间可能就很晚,那么就会导致关闭时间更晚。
  3. 对数据库造成压力。 定时任务集中扫表,这会使得数据库IO在短时间内被大量占用和消耗,如果没有做好隔离,并且业务量比较大的话,就可能会影响到线上的正常业务。
  4. 分库分表问题。 订单系统,一旦订单量大就可能会考虑分库分表,在分库分表中进行全表扫描,这是一个极不推荐的方案。

使用场景:
定时任务的方案,适合于对时间精确度要求不高、并且业务量不是很大的场景中。如果对时间精度要求比较高,并且业务量很大的话,这种方案不适用。

4. 懒延时模式

业务上的被动关闭是一种简单的解决方案。在订单创建后,系统不主动关闭订单,而是等待用户来访问订单。当用户访问订单时,系统检查订单的支付状态和时间,如果订单未支付且已超时,则进行关单操作。

实现步骤:

  1. 在订单创建后,不执行主动关单操作。
  2. 当用户访问订单时,检查订单的支付状态和时间。
  3. 如果订单未支付且已超时,进行关单操作并提示用户。

优点:

实现简单,基本不需要开发定时关闭功能。

缺点:

  1. 如果用户一直不来查看订单,会导致数据库中存在大量未关闭的脏数据。
  2. 需要在用户查询过程中进行写操作,可能影响性能和稳定性。
  3. 影响查询之外的业务(如:统计、库存),影响查询效率。

5. Redis方案

方式一:过期监听

Redis 是一个高性能的 KV 数据库,除了用作缓存以外,其实还提供了过期监听的功能。其本质是注册一个 listener,利用 redis 的发布订阅,当 key 过期时,发布过期消息(key)到 Channel 的指定Topic中。

实现步骤:

  1. 在 redis.conf 中,配置 notify-keyspace-events Ex 即可开启此功能。
  2. 在代码中继承 KeyspaceEventMessageListener,实现 onMessage 就可以监听过期的数据量。
  3. 在实际的业务中,我们可以将订单的过期时间设置比如 30 分钟,然后放入到 redis。30 分钟之后,就可以消费这个 key,然后做一些业务上的后置动作,比如检查用户是否支付。

在这里插入图片描述
优点:
由于 redis 的高性能,所以我们在设置 key,或者消费 key 时,速度上是可以保证的。

缺点:

  1. 我们得要先知道Redis删除过期key的策略,分别有两种,一种是定期删除,一种是惰性删除。定期删除就是过一段时间,就会随机抽取一批设置了过期时间的key,检查是否过期,过期则清理,这样限制了执行时长避免影响业务,惰性删除就是不主动去删除过期key,每次访问的时候才会进行删除。所以你看出来了吗,Redis的key删除策略是不精准的,订单量大的话弊端就会显露出来。
  2. 还有就是Redis过期通知也是不可靠的,Redis在过期通知的时候,如果应用正好重启了,那么就有可能通知事件就丢了,会导致订单一直无法关闭,有稳定性问题。

所以总结下来,redis 的过期订阅相比于其他方案没有太大的优势,在实际生产环境中,用得相对较少。

方式二:Redisson分布式延迟队列

Redisson 除了提供我们常用的分布式锁外,还提供了一个分布式延迟队列 RDelayedQueue,是一种基于 Redis Zset 结构的延时队列实现。DelayQueue 中有一个名为 timeoutSetName 的有序集合,其中元素的 score 为投递时间戳。
DelayQueue 会定时使用 zrangebyscore 扫描已到投递时间的消息,然后把它们移动到就绪消息列表中。

在这里插入图片描述

它的稳定性以及可靠性还是不错的,在保证Redis稳定地情况下,可以推荐使用,具体实现可以看下这篇文章Redisson实现延迟队列。后续我也会给大家做下示例。

但是要注意:

  1. Redisson的的RDelayedQueue是基于Redis实现的,而Redis本身并不保证数据的持久性。如果Redis服务器宕机,那么所有在RDelayedQueue中的数据都会丢失。因此,我们需要在应用层面进行持久化设计,例如定期将RDelayedQueue中的数据持久化到数据库。
  2. 随着RDelayedQueue中数据量的增长,后台线程的检查频率和处理速度可能会成为瓶颈,影响系统的并发性能。因此,我们需要对后台线程进行适当的优化,例如使用多线程进行处理,或者调整检查频率。

处理思路:

  1. 合理设计延迟时间:在设计延迟任务时,我们应该根据实际需求来合理设置延迟时间,避免设置过长的延迟时间导致内存占用过高。
  2. 利用Redisson的的持久化机制:Redisson提供了多种持久化机制,例如RDB和AOF。我们可以利用这些机制来定期将RDelayedQueue中的数据持久化到磁盘,以确保数据的安全性。
  3. 监控和告警:我们应该注意监控RDelayedQueue的状态和性能,例如检查队列的长度、后台线程的处理速度等。当发现异常情况时,应该及时告警并进行处理。

6. 利用数据库的定时任务功能

一些数据库(如MySQL)提供了定时任务功能,我们可以利用它来实现订单超时关闭。在订单创建时,记录订单的创建时间和超时时间。然后,通过数据库的定时任务定期检查订单的支付状态,如果订单未支付且已超时,则将其状态设置为关闭。

实现步骤:

  1. 在订单创建时,记录订单的创建时间和超时时间。
  2. 设置数据库的定时任务,定期检查对应订单的支付状态。
  3. 如果订单未支付且已超时,将其状态设置为关闭,并执行后续处理逻辑。

优点:

  1. 利用数据库的内置功能,无需额外开发定时任务系统。
  2. 定时任务与业务逻辑紧密集成,方便管理和维护。

缺点:

  1. 这种就纯粹依靠数据库来实现了,需要用到数据库的事件功能,如果在数据库集群的情况下,我们需要评估这种方式的可行性和复杂性,同时当数据量比较大的时候,对数据库的压力也是比较大的。同时异常情况的可追溯性不强,所以不推荐使用。

7. JDK延迟队列

JDK延时队列DelayQueue是一个无界阻塞队列,该队列只有在延迟期满的时候才能从中获取元素。
在这里插入图片描述

优点:

  • 不需要借助任何外部的资源,直接基于应用自身就能实现。

缺点:

  • 只适合在单机场景、并且数据量不大的场景中使用,如果涉及到分布式场景,那还是不建议使用。
  • 订单量太大的话,可能会导致OOM的问题。
  • DelayQueue是基于JVM内存的,一旦机器重启了,里面的数据就都没有了。

使用场景:
只适合demo测试。

总结

经过咱们上面的讨论,其实在实际开发中,我们可以这样选择:

  1. 如果项目中使用的消息中间件是RabbitMQ或RocketMQ,对延迟精度要求较高,业务量较大,不想对Redis有太大压力的,推荐使用方式1。
  2. 如果项目中使用的消息中间件是Kafka,对延迟精度要求较高,业务量较大,不想对Redis有太大压力的,推荐使用方式2。
  3. 如果项目中没有使用消息中间件,后续也不打算引入,业务量不大,对消息丢失有一定的容忍,可以采用Redisson策略。
  4. 如果项目中不想用中间件或者Redis来处理,同时业务量不大,对延迟有一定的容忍,简单起见可以采用定时轮询策略。

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

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

相关文章

政务大数据解决方案(六)

政务大数据解决方案通过构建全面的数据集成平台,将来自不同政府部门和公共服务领域的多维度数据汇聚起来,运用先进的数据分析和人工智能技术进行深度挖掘与预测,从而为政府提供实时、精准的信息支持,优化决策流程,提高…

工业4.0下的防勒索病毒策略:主机加固在工控机防病毒中前行

MCK主机加固产品是一款专注于数据安全解决方案的软件,它在防勒索病毒和工控机防病毒方面具备一系列独特的功能和优势。 防勒索病毒方面: 内核级签名校验技术:MCK系统通过这项技术对操作系统启动及加载的所有模块进行可信认证,确…

电脑只有一个盘怎么分区?单盘电脑的解决方案

在现代计算机使用中,硬盘分区是一个重要的环节,它有助于我们更好地管理数据、提高系统运行效率,并在一定程度上保护数据的安全。 然而,当我们购买了一台新电脑后发现电脑里只有一个硬盘分区,这时候我们可能就需要对电…

Golang | Leetcode Golang题解之第349题两个数组的交集

题目&#xff1a; 题解&#xff1a; func intersection(nums1 []int, nums2 []int) (res []int) {sort.Ints(nums1)sort.Ints(nums2)for i, j : 0, 0; i < len(nums1) && j < len(nums2); {x, y : nums1[i], nums2[j]if x y {if res nil || x > res[len(re…

什么是CDN,CDN的作用是什么?

CDN CDN英文全称Content Delivery Network&#xff0c;即为内容分发网络。它是建立并覆盖在承载网之上&#xff0c;将内容存储在分布式的服务器上&#xff0c;使⽤户可以从距离较近的服务器获取所需的内容&#xff0c;从⽽减少数据传输的时间和距离&#xff0c;提⾼内容的传输…

基于Java的同城宠物服务预约系统的设计与实现---附源码78744

摘要 随着人们对宠物的喜爱和关注度不断增加&#xff0c;对宠物服务的需求也日益增长。为了提供更便捷、高效的宠物服务&#xff0c;设计并实现了一款基于 Java 的同城宠物服务预约系统。 本系统旨在满足宠物主人对各种宠物服务的需求&#xff0c;同时为宠物服务提供者提供一个…

C++ 设计模式——抽象工厂模式

抽象工厂模式 抽象工厂模式 抽象工厂模式主要组成部分代码实现抽象工厂模式模式的 UML 图抽象工厂模式 UML 图解析优点和缺点适用场景 抽象工厂模式提供一个接口&#xff0c;用于创建一系列相关或相互依赖的对象&#xff0c;而无需指定它们的具体类。它通常用于需要创建多个产品…

电脑怎么截图?截屏电脑快捷键ctrl加什么?

截图是我们日常使用电脑过程中非常常见的操作之一。无论是想保存有用的信息、分享有趣的内容&#xff0c;还是记录某个错误信息&#xff0c;截图都是一个简单而有效的方式。但是&#xff0c;不同的操作系统和需求会决定使用不同的方法来截图。接下来&#xff0c;我们将详细介绍…

opencascade Bnd_Range源码学习区间计算

opencascade Bnd_Range 前言 这个类描述了由两个实数值限定的 1D 空间中的区间。 一个区间可以是无效的&#xff0c;这表示区间中不包含任何点。 方法 1 默认构造函数。创建一个无效区间。 Bnd_Range() &#xff1b; 2 构造函数。创建最小最大值区间 Bnd_Range(const Sta…

使用LoRA对Llama3微调

使用LoRA&#xff08;Low-Rank Adaptation of Large Language Models&#xff09;技术对Llama-3语言模型进行微调。 理论知识参考百度安全验证 微调的前提条件 现在huggingface上下载llama2或llama3的huggingface版本。 我下载的是llama-2-13b-chat。 大语言模型微调方法 …

ComfyUI的部署,Ubuntu22.04系统下——点动科技

在服务器Ubuntu22.04系统下&#xff0c;ComfyUI的部署 一、ubuntu22.04基本环境配置1.1 更换清华Ubuntu镜像源1.2 更新包列表&#xff1a;2. 安装英伟达显卡驱动2.1 使用wget在命令行下载驱动包2.2 更新软件列表和安装必要软件、依赖2.2 卸载原有驱动2.3 安装驱动2.4 安装CUDA2…

【实战】分组校验

在实际的业务场景中同一个Entity的校验可能会有不同的规则&#xff0c;比如添加数据品牌id必须为空&#xff0c;而更新数据品牌Id必须不为空&#xff0c;针对这种情况我们需要使用分组校验来实现 在Entity中指定分组规则 使用 /*** 保存*/RequestMapping("/save")pub…

[STM32]如何正确的安装和配置keil?(详细)

一、我们为什么需要keil? 对于嵌入式开发的硬件来讲STM32可以说有着不可撼动的地位&#xff0c;它可能是很多人入门嵌入式开发接触到的第一款芯片&#xff0c;其强大的生态和大量开放的源代码也深受开发者的喜爱。对于嵌入式开发的软件来讲&#xff0c;keil绝对是在一届软件中…

知识竞赛中限时答题环节竞赛规则有哪些设计方案

限时答题在知识竞赛活动中是一个比较新颖的玩法&#xff0c;通过在一定时间内快速答题来提高现场紧张气氛&#xff0c;达到很好的现场效果。这种方式要求选手不但要答题正确&#xff0c;还要答题速度。那么&#xff0c;常用的限时答题环节规则应怎么设计呢&#xff1f;下面列出…

智能数字矿山钻机机械设备类网站模板

智能数字矿山钻机设备类网站模板&#xff0c;非常高端大气上档次&#xff01;易优内容管理系统是一套专注中小型企业信息传播解决方案的管理系统&#xff0c;更是一套后台管理框架&#xff0c;可以通过个性定制导航入口&#xff0c;扩展前端多个场景&#xff0c;比如可以用于小…

后端开发刷题 | 链表内指定区间反转【链表篇】

描述 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转&#xff0c;要求时间复杂度 O(n)O(n)&#xff0c;空间复杂度 O(1)O(1)。 例如&#xff1a; 给出的链表为 1→2→3→4→5→NULL1→2→3→4→5→NULL, m2,n4 返回 1→4→3→2→5→NULL 数据范围&#xff1a; 链表…

【Linux】【系统纪元】Linux基础指令

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C游记》《进击的C》《Linux迷航》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、文件管理1.1 ls1.2 pwd1.3 cd1.4 mkdir1.5 touch1.6 rm1.7 cp1.8 mv 二、文件输出2.1 echo2.2 cat2.3 less…

新学期新动力,以骨传导耳机开启健康音乐之旅

大学生快开学啦&#xff01;激励自己在学期的状态给自己准备一个礼物应该不过分吧&#xff0c;相信没有大学生能够没有耳机&#xff01;不管是在赶早八的路上也要放收歌来醒醒神&#xff0c;还是日常散步不那么单调&#xff0c;使用频率都很高&#xff0c;但是入耳式的蓝牙耳机…

Stable Diffusion 提示词插件:开启个性化艺术创作大门,探索AI绘画新境界。让灵感枯竭再无可能!

前言 之前的文章介绍了提示词的基础用法和进阶用法&#xff0c;东西很多很复杂&#xff0c;那么非程序员相关行业的人员&#xff0c;对字符不敏感怎么办&#xff1f; 没关系&#xff0c;今天我来介绍几款提示词插件&#xff0c;可以大大提升 Stable Diffusion 的使用效率。 …

微信怎么恢复聊天记录?轻松4招,恢复消失的聊天记录

微信聊天记录不仅是日常沟通的桥梁&#xff0c;更是珍贵记忆的储存库。然而&#xff0c;误删、系统故障或设备更换等意外情况&#xff0c;时常让我们的聊天记录瞬间消失&#xff0c;给我们留下遗憾。面对这一挑战&#xff0c;微信怎么恢复聊天记录成为许多人的迫切需求。幸运的…