脱离八股文,真实开发中的延时处理需求实现思路(超时订单处理为例)

news2024/9/21 16:35:55

前言

        咱们聊聊那些在开发过程中经常遇到的延时处理需求吧。比如说,网购时那些迟迟不付款的订单,或者是社交软件里那些需要稍后处理的消息,再或者是金融交易中那些需要等待确认的交易。这些都是咱们得搞定的活儿。

        不过,很多时候,咱们看到的文章或者面试题,好多都是为技术而技术,感觉就像是空中楼阁,只谈理论,不接地气。很多人可能连自己说的方案能不能行都不知道,就敢拿出来说。说实话,这种只谈技术不谈实际应用的情况,真的挺让人头疼的。

        所以,今天咱们就来点实在的。咱们不聊那些高大上的理论,而是聊聊在实际工作中,这些延时处理需求到底是怎么搞定的。这里采用大家都比较熟悉的一个业务场景:超时订单失效来作为需求设计,咱们会分享一些公司中真实落地的案例,看看这些方案在真实环境中到底是怎么落地的,希望能给咱们的读者朋友们带来一些实实在在的帮助和启发。

需求背景

        想象一下,顾客在电商平台上选了一堆东西,结果过了半天也没付款,这订单就悬那儿了。这时候,咱们得有个机制来自动处理这些订单,比如取消订单,释放库存,或者给顾客发个提醒,看他们是否还要继续购买。这事儿得做得既及时又高效,不能让顾客等太久,也不能让系统因为处理这些订单而变慢。设计的时候,咱们得考虑怎么设置合理的超时时间,怎么优雅地处理订单取消流程,还得确保这个处理过程不影响其他用户的购物体验。简单来说,就是得让系统既能快速反应,又得稳定可靠。

实现方案一:懒延时被动关闭

        首先,客户端(比如一个手机App或者网页)在拉取订单的时候,会同时从服务器获取当前的时间戳和订单的超时时间。客户端拿到这些信息后,会自己计算:当前时间减去订单的超时时间,看结果是不是大于订单的创建时间。如果是,那就说明订单已经超时了。客户端就会在界面上给用户一个明确的提示,比如显示“订单已超时”或者用不同的颜色标记(或者未支付订单直接消失),让用户知道这个订单已经不能继续付款了。同时,客户端会悄悄地(隐式地)向服务器发送一个请求,告诉服务器:“嘿,这个订单超时了。”这个请求不需要用户干预,是自动进行的。服务器收到客户端的超时请求后,就会进行相应的处理,比如更新数据库中的订单状态,标记为“已关闭”或者“超时”,并释放订单占用的库存或者资源。后续查询订单列表直接就可以基于订单状态来过滤掉该超时订单。

         这个方案的好处是减轻了服务器的负担,因为服务器不需要定时去检查每个订单的状态。适用于数据量比较小的业务场景,总的来说,这个方案就是让客户端多做一些工作,服务器端则更轻松一些。但是这个方案有可能导致大量脏数据堆积问题,所以可以再配合一个方案二来进一步优化,这样既能提高系统的响应速度,也能节省服务器资源。不过,实现的时候要注意各种异常情况的处理,确保系统的稳定性和准确性。

实现方案二:定时任务周期轮询数据库批处理

        每当用户下单时,系统会计算出一个超时时间戳并保存到数据库中;接着,通过xxl-job设置一个定时任务,每隔5秒,系统就会查询数据库中所有超时时间戳小于当前时间并且订单状态为待支付的订单( order_status = '待支付' && pay_expire_time<now);通过对超时时间戳字段建立了索引,这样的查询既快速又高效,即使面对数百万订单也能稳定运行;一旦检测到超时订单,系统会自动执行后续处理,如更新订单状态、释放库存等,同时,整个过程会有详细的日志记录和监控,如果发现任务执行失败或者超时,及时发送报警通知给运维人员。并且在正式环境部署之前,可以先在小范围内进行灰度发布,观察系统的表现,确保方案的可行性和稳定性。

        这个基于定时轮询处理超时未支付订单的方案适用于那些数据量较大,对订单处理时效性要求不是非常严格的业务场景,特别是在系统资源有限或需要简单处理机制的情况下,它能够提供一种易于实现、监控和维护的解决方案。尽管存在一定的处理延迟,并且可能在高流量时段无法立即响应所有订单,但通过合理设置轮询间隔,可以有效平衡服务器负载和业务需求,确保系统的稳定性和可靠性。不过,对于需要快速响应或处理大量订单的系统,可能需要考虑更高效的处理策略,如消息队列或事件驱动模型,以提高处理效率和实时性。

实现方案三:MQ延时消息

        利用消息队列(MQ、或者Redis的Stream流)的延时消息特性来处理超时未支付订单的问题。当用户创建订单时,系统会向MQ发送一条设定了延时时间的消息,这个延时时间与订单的超时时间相匹配。如果到了延时时间用户还未支付,MQ会将消息发送给消费者,由消费者来执行超时订单的相关处理逻辑。

        这个方案适用于搭建了 RocketMQ的公司,想利用 RocketMQ的延时消息来实现该功能,优点在于利用中间件 MQ的特性,避免业务端自己实现,并且自带有持久化、重试机制等保证消息的正确消费,但是如果使用开源的 Apache RocketMQ 4.x版本,消息延时只有特定的 18个级别,所以业务的超时时间要和 RocketMQ的延时级别相匹配才能使用,并且对于开源版的 RocketMQ没有删除延时消息的功能,因此需要对每条消息都做超时判断,增加了很多无效的数据处理,同一个时刻大量消息会导致消息延迟:定时消息的实现逻辑需要先经过定时存储等待触发,定时时间到达后才会被投递给消费者。因此,如果将大量定时消息的定时时间设置为同一时刻,则到达该时刻后会有大量消息同时需要被处理,会造成系统压力过大,导致消息分发延迟,影响定时精度。并且每个订单需要新增一个定时消息,且不会马上消费,给MQ带来很大的存储成本。

不推荐:Redis的过期监听

 这个方案表面看起来没问题,但是在实际生产上不推荐,我们来看下Redis过期时间的原理

每当我们对一个key设置了过期时间,Redis就会把该key带上过期时间,存到过期字典中,在redisDb中通过expires字段维护:

typedef struct redisDb {
    dict *dict;    /* 维护所有key-value键值对 */
    dict *expires; /* 过期字典,维护设置失效时间的键 */
    ....
} redisDb;

过期字典本质上是一个链表,每个节点的数据结构结构如下:

  • key是一个指针,指向某个键对象。
  • value是一个long long类型的整数,保存了key的过期时间。

Redis主要使用了定期删除和惰性删除策略来进行过期key的删除

  • 定期删除:每隔一段时间(默认100ms)就随机抽取一些设置了过期时间的key,检查其是否过期,如果有过期就删除。之所以这么做,是为了通过限制删除操作的执行时长和频率来减少对cpu的影响。不然每隔100ms就要遍历所有设置过期时间的key,会导致cpu负载太大。
  • 惰性删除:不主动删除过期的key,每次从数据库访问key时,都检测key是否过期,如果过期则删除该key。惰性删除有一个问题,如果这个key已经过期了,但是一直没有被访问,就会一直保存在数据库中。

        从以上的原理可以得知,Redis过期删除是不精准的,在订单超时处理的场景下,惰性删除基本上也用不到,无法保证key在过期的时候可以立即删除,更不能保证能立即通知。如果订单量比较大,那么延迟几分钟也是有可能的。

Redis过期通知也是不可靠的icon-default.png?t=O83Ahttps://redis.io/docs/manual/keyspace-notifications/        Redis在过期通知的时候,如果应用正好重启了,那么就有可能通知事件就丢了,会导致订单一直无法关闭,有稳定性问题。如果一定要使用Redis过期监听方案,建议再通过定时任务做补偿机制。

总结

  • 如果数据量较小,推荐使用懒延时 + 定期数据库轮询标注的方案,提高系统的响应速度,也能节省服务器资源
  • 如果对于超时精度比较高,超时时间在24小时内,且不会有峰值压力的场景,推荐使用RocketMQ的定时消息解决方案。
  • 如果对于超时精度没有那么敏感,并且有海量订单需要批处理,推荐使用基于定时任务的跑批解决方案。

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

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

相关文章

JS面试真题 part3

JS面试真题 part3 11、bind、call、apply区别&#xff1f;如何实现一个bind12、JavaScript中执行上下文和执行栈是什么13、说说JavaScript中的事件模型14、解释下什么是事件代理&#xff1f;应用场景&#xff1f;15、说说你对闭包的理解&#xff1f;闭包使用场景 11、bind、cal…

make 程序规定的 makefile 文件的书写语法

&#xff08;1&#xff09; 常用的 gcc 选项&#xff1a; &#xff08;2&#xff09; make 的作用&#xff1a; &#xff08;3&#xff09; 搭建 make 的实验环境 &#xff0c; linux 的很简单&#xff0c; windows 的复杂一点&#xff1a; windows 上 make 环境的搭建&#…

python爬虫基础:了解html

编辑器vscode <!DOCTYPE html> <html><head><title>第一个网页</title></head><body><h1>字体</h1><h2>字体</h2><h3>字体</h3><p>Lorem, ipsum dolor sit amet consectetur adipisicing…

电商平台如何实现自动监控订单签收状态,加快资金划拨进程?

资金划拨作为交易流程的核心环节之一&#xff0c;直接关系到商家资金回笼的速度、消费者购物体验的满意度以及平台自身的信誉与稳定性。 区别于自营电商&#xff0c;电商平台入驻了许多第三方商家&#xff0c;为了保障交易安全和控制风险&#xff0c;在交易未完成之前&#xff…

Java 入门指南:Java 并发编程 —— 同步工具类 Semephore(信号量)

文章目录 同步工具类Semephore核心功能限制并发访问量公平与非公平策略灵活性与适应性 常用方法使用示例 同步工具类 JUC&#xff08;Java.util.concurrent&#xff09;是 Java 提供的用于并发编程的工具类库&#xff0c;其中包含了一些通信工具类&#xff0c;用于在多个线程之…

Spring和MyBatis常见面试题总结

文章目录 1 Spring 基础1.1 说一下你对 Spring 的理解&#x1f525;1.2 Spring,Spring MVC,Spring Boot 之间什么关系?1.3 Spring 框架中用到了哪些设计模式&#xff1f;&#x1f525;1.4 说说自己对于 Spring MVC 了解?1.5 Spring MVC 的核心组件有哪些&#xff1f;1.6 Spri…

flutter开发实战-GoRouter路由go与push区别实践

flutter开发实战-GoRouter路由go与push区别实践 GoRouter是一个flutter的声明性路由包&#xff0c;使用路由器API提供一个方便的、基于url的API&#xff0c;用于在不同屏幕之间导航。可以定义URL模式、使用URL导航、处理深度链接以及许多其他与导航相关的场景。 之前使用了Go…

Vue3封装table表格右键菜单功能

1) 效果&#xff0c;右键单击单元格&#xff0c;打开菜单弹窗: 点击菜单选项&#xff0c;可选择只读/编辑&#xff0c;可在只读/编辑方法中&#xff0c;拿到该行列表格的数据&#xff0c;进行相关操作 2) 思路 1、右键菜单组件 出现的时机&#xff0c;是右键单击table表格row-…

移动安全需求分析与安全保护工程

移动应用安全威胁与需求分析 移动应用系统组成&#xff1a; 移动应用&#xff1a;简称App 通信网络&#xff1a;无线网络&#xff0c;移动通信网络及互联网 应用服务端&#xff1a;由相关服务器构成&#xff0c;负责处理来自App相关信息或数据 移动应用安全分析 Android系统…

【0基础】制作HTML网页小游戏——贪吃蛇(附详细解析)

我在昨天的文章&#xff08;贪吃蛇HTML源码&#xff09;里面分享了网页版贪吃蛇小游戏的源码&#xff0c;今天就来给大家详细讲解一下每部分代码是如何运作的&#xff0c;以及以后要如何美化贪吃蛇的UI界面&#xff0c;在哪里修改等。 目录 一、代码运作 1、HTML结构: 2、C…

数组的常用算法

数组是同类型数据的集合。便于整体处理数据&#xff0c;数组操作的主要算法有&#xff1a; 1求极值 2查找 3排序 2查找 cprimer plus第11.1节278--279页 4数组和指针的区别&#xff1a;数组表示法和指针表示法 数组表示法1 int a[4]{2,4,1,5}; for(int i0;i<4;i)cou…

JAVA 的excel数据批量导入解析 现在都用什么API工具 Apache POI 、EasyExcel 、easypoi有什么区别

&#x1f4dd;个人主页&#x1f339;&#xff1a;个人主页 ⏩收录专栏⏪&#xff1a;SpringBoot &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339;&#xff0c;让我们共同进步&#xff01; 在Java中&#xff0c;处理Excel数据批量导入解析时&#xff0c;常…

通讯录

在写一个程序前需要了解的知识&#xff0c;需要对通讯录的流程了如指掌&#xff0c;才能写出一个完整的程序 。 写一个主函数&#xff0c;里面包含菜单、对菜单的选择、以及循环。创建个人信息结构体&#xff0c;多人构成的结构体数组。分析每一个函数&#xff1a; 1).增加信…

webstorm修改主题色和配色常用插件(全部实用)包含主题、界面、开发效率等

Windows 用户打开setting 选择配色 更换主题看这里 效率插件 Rainbow Brackets 推荐理由&#xff1a;用各种鲜明的颜色显示括号&#xff0c;这样可以很容易分清楚括号配对问题。 Key promoter 推荐理由&#xff1a;只要是鼠标操作能够用快捷键替代的&#xff0c;Key Promoter…

若依漏洞综合利用工具

若依漏洞综合利用工具 安装与使用 该工具使用java开发&#xff0c;环境要求&#xff1a;JDK1.8版本 java -jar “文件名” 即可打开图形化界面。 注意查看"必看操作说明"模块。 1.首先下载好几个必要模块。 然后把openjfx-17.0.11_windows-x64_bin-sdk放在D盘根…

音视频入门基础:AAC专题(1)——AAC官方文档下载

一、AAC简介 高级音频编码&#xff08;英语&#xff1a;Advanced Audio Coding&#xff0c;AAC&#xff09;是有损音频压缩的专利数字音频编码标准&#xff0c;由Fraunhofer IIS、杜比实验室、贝尔实验室、Sony、Nokia等公司共同开发。出现于1997年&#xff0c;为一种基于MPEG…

【python因果推断库14】饮酒年龄 - 贝叶斯分析

目录 饮酒年龄 - 贝叶斯分析 主效应模型 交互模型 将连续变量以治疗阈值为中心 饮酒年龄 - 贝叶斯分析 这个例子使用了回归断点设计来探讨最低合法饮酒年龄&#xff08;在美国为21岁&#xff09;对全因死亡率的因果效应。数据集来自carpenter2009effect 的一项研究。 impo…

C语言蓝桥杯:语言基础

竞赛常用库函数 最值查询 min_element和max_element在vector(迭代器的使用) nth_element函数的使用 例题lanqiao OJ 497成绩分析 第一种用min_element和max_element函数的写法 第二种用min和max的写法 二分查找 二分查找只能对数组操作 binary_search函数&#xff0c;用于查找…

yolov8实现图片验证码识别

1、环境准备 1.1、安装miniconda 地址&#xff1a;Index of /anaconda/miniconda/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 注意&#xff1a;为避免不兼容的问题&#xff0c;推荐下载py38版本&#xff0c;我下载的是Miniconda3-py38_23.1.0-1-Windows-x86_…

【Java 类与对象】多态

空山新雨后 天气晚来秋 目录 多态的概念 多态实现条件 多态的转型 向上转型 向下转型 instanceof 关键字 方法的重写 Override注解 重写的权限 只能重写继承而来的方法&#xff08;1&#xff09; final、static 不能被重写&#xff08;2&#xff09; 重写的方法不能带有等级更严…