后端与系统架构图文讲义2567 字

如何实现15分钟未支付自动取消订单

·全库 595 / 611

《如何实现15分钟未支付自动取消订单》共 8 页、0.3 万字,通篇围绕 Redis、延迟、缓存、数据库 展开,归在「后端与系统架构」这一层。

覆盖Redis延迟缓存数据库MySQL需求

适合给 AI 系统搭底座、要管得住的人

目录骨架(6 节)
  1. 如何实现 15 分钟未支付自动取消订单?
  2. 方案 3:时间轮算法
  3. 实现细节
  4. 方案 1:数据库轮询
  5. RocketMQ 延迟队列
  6. RabbitMQ 及其他利用死信队列

原 PDF 已逐页还原成图,共 8 页,这里先放前 3 页,其中 2 页识别出了标题。右侧文字由 OCR 按版面重排,可能有个别错字,以图为准;点图可全屏放大。

本讲义目录 · 3 页
  1. 01如何实现 15 分钟未支付自动取消订单?
  2. 02通过 Poll0/take0 方法获…
  3. 03方案 3:时间轮算法
011 / 3
第 1 页:如何实现 15 分钟未支付自动取消订单?
第 1 页

如何实现 15 分钟未支付自动取消订单?

在开发中,往往会遇到一些关于延时任务的需求。

  • 例如
  • 生成订单 15 分钟未支付,则自动取消
  • 生成订单 60 秒后,给用户发短信 对上述的任务,我们给一个专业的名字来形容,那就是延时任务。那么这里就会产生一个问题,这个延 时任务和定时任务的区别究竟在哪里呢?一共有如下几点区别 定时任务有明确的触发时间,延时任务没有 定时任务有执行周期,而延时任务在某事件触发后一段时间内执行,没有执行周期 定时任务一般执行的是批处理操作是多个任务,而延时任务一般是单个任务 下面,我们以判断订单是否超时为例,进行方案分析

方案 1:数据库轮询

思路 该方案通常是在小型项目中使用,即通过一个线程定时的去扫描数据库,通过订单时间来判断是否有超 时的订单,然后进行 update 或 delete 等操作

单体应用:利用 Spring-Task 或者 Quartz 等单机任务调度工具定时执行

集群环境:比如利用分布式任务调度工具 XXL-JOB 执行分布式任务调度

定时任务

调度层

业务逻辑

单机版

ScheduleExecutoerService

DelayQueue

Timer

单线程永动机

HashWheelTimer

022 / 3
第 2 页
第 2 页

通过 Poll0/take0 方法获…

集群版

Elastic-Job

Power-Job

DelayedQueue

Delayed Delayed

通过 Poll0/take0 方法获得 一个任务

消费者

Consumer

XXL-JOB

生产者生成一个任务

优点 简单易行,支持集群操作,小项目首选 缺点

  • 对服务器内存消耗大
  • 存在延迟,比如你每隔 3 分钟扫描一次,那最坏的延迟时间就是 3 分钟
  • 假设你的订单有几干万条,每隔几分钟这样扫描一次,数据库损耗极大
  • xxl-job 不是所有项目都有

思路 该方案是利用 JDK 自带的 DelayQueue 来实现,这是一个无界阻塞队列,该队列只有在延迟期满的时候 才能从中获取元素,放入 DelayQueue 中的对象,是必须实现 Delayed 接口的,DelayedQueue 实现工

作流程如下图所示

生产者

Producer

其中 Poll (:获取并移除队列的超时元素,没有则返回空 take ():获取并移除队列的超时元素,如果没有则 wait 当前线程,直到有元素满足超时条件,返回结果。

033 / 3
第 3 页:方案 3:时间轮算法
第 3 页

方案 3:时间轮算法

优点 效率高,任务触发时间延迟低。 缺点 • 服务器重启后,数据全部消失,怕宕机

  • 因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现 OOM 异常
  • 代码复杂度较高

思路 先上一张时间轮的图

时间轮算法可以类比于时钟,如上图箭头(指针)按某一个方向按固定频率轮动,每一次跳动称为一个 tick。这样可以看出定时轮由个 3 个重要的属性参数,ticksPerWheel (一轮的 tick 数),tickDuration (一个 tick 的持续时间)以及 timeUnit (时间单位),例如当 ticksPerWheel=60,tickDuration=1, timeUnit=秒,这就和现实中的始终的秒针走动完全类似了。 如果当前指针指在 1 上面,我有一个任务需要 4 秒以后执行,那么这个执行的线程回调或者消息将会被 放在 5 上。那如果需要在 20 秒之后执行怎么办,由于这个环形结构槽数只到 8,如果要 20 秒,指针需 要多转 2 圈。位置是在 2 圈之后的 5 上面(20%8+1)

优点 效率高,任务触发时间延迟时间比 delayQueue 低,代码复杂度比 delayQueue 低。

缺点

  • 服务器重启后,数据全部消失,怕宕机
  • 集群扩展相当麻烦
  • 因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现 0OM 异常

资料里没有你的场景?

把你手上的数据和想解决的那个环节发上来,我们按具体情况回,不复述方法论。

发布需求