场景——订单

一、订单超时的解决方案

描述:购物下单后没有付款。系统超时30分钟自动关闭订单。

方案:

方案 场景 优点 缺点
JDK 自带的延时队列 小型单机应用,非核心业务

实现简单,基于 JDK 自带 API,无需额外组件;

仅适用于单机环境,不支持分布式;

数据在内存中 DelayQueue,服务重启后,队列中的任务会丢失;

无法应对大量订单场景,容易造成内存溢出。

Redis 的过期监听 中小规模分布式应用,对时效性要求不高的场景

实现相对简单,利用 Redis 的过期机制;

支持分布式,可在多节点部署监听;

无需复杂的任务调度逻辑

Redis 的过期删除并非实时,存在延迟;(定期删除、惰性删除

监听机制可能存在消息丢失风险;

当过期键数量较多时,可能影响 Redis 性能。

常用★★★基于 MQ 的延时消息 中大规模分布式应用,核心业务,对可靠性和时效性要求较高

可靠性高,支持消息持久化,服务重启后消息不丢失;

时效性较好,不同 MQ 能提供不同精度的延时;

支持分布式,可扩展性强;

能应对高并发场景

需要引入 MQ 组件,增加了系统复杂度;

部分 MQ 的延时消息功能需要额外配置或开发;

可能存在一定的消息投递延迟

常用★★★分布式定时任务批处理 大规模分布式应用,对时效性要求不高,订单量极大的场景

支持分布式,能有效应对海量订单;

可靠性高,可通过任务重试机制保证处理结果;

可根据业务需求灵活设置调度周期

实现复杂,需要搭建分布式定时任务框架;

时效性较差,依赖任务调度周期,可能存在订单超时后一段时间才被处理的情况;

批量处理时,若处理逻辑复杂,可能影响性能

1 RabbitMQ 的延时消息:

  1. 业务发送一个延时消息,我们把消息写入到对应的队列。
  2. 可以设置队列的 TTL(存活时间),当消息超时后,进入死信交换机。
  3. 定义一个 BizQueue 用来接收死信消息,进行业务的消费。

  优点:

    • 可以支持海量延时消息,支持分布式处理。

  缺点:

    • 不灵活,只能支持固定延时等级;
    • 使用复杂,要配置一堆延时队列;

2 RocketMQ 的定时消息:

  1. 业务发送一个定时消息。
  2. 到了时间,RocketMQ 会通知客户端去处理。(时间轮算法)

优点:

    • 使用简单,和使用普通消息一样。
    • 支持分布式。
    • 精度高,支持任意时刻。

缺点:

    • 定时时长最大值 24 小时。
    • 成本高:每个订单需要新增一个定时消息,且不会马上消费,给MQ带来很大的存储成本
    • 同一个时刻大量消息会导致消息延迟:定时消息的实现逻辑需要先经过定时存储等待触发,定时时间到达后才会被投递给消费者。因此,如果将大量定时消息的定时时间设置为同一时刻,则到达该时刻后会有大量消息同时需要被处理,会造成系统压力过大,导致消息分发延迟,影响定时精度。

3 (推荐)定时任务分布式批处理:

利用 SchedulerX 的分布式调度能力,定期(如每 1 分钟)触发任务,批量扫描数据库中 “已创建但未支付且已超时” 的订单,执行关闭操作(更新状态、释放库存等)。

关键组建:

    • SchedulerX 调度中心:负责任务的分发、监控和失败重试;
    • 执行器(Worker):部署在业务服务中,接收调度任务并执行具体逻辑;
    • 分片策略:通过分片将海量订单分散到多个执行器并行处理,提高效率。

实现流程:

    1. 任务配置:在 SchedulerX 控制台创建定时任务;
    2. 分片逻辑实现:执行器接收到任务后,根据分片索引拆分订单 ID 范围,避免重复处理;
    3. 可靠性保障:失败重试(自定义配置)、幂等性处理、监控告警(任务失败或超时)

   

二、10W QPS 如何防止重复下单?

发生重复下单的常见场景:

  • 短时间内多次点击下单按钮
  • 服务超时重试

思路:

属于接口幂等性问题,一锁二判三更新

  • 一锁:先加锁,可以加分布式锁、悲观锁都可以,但是一定是一个互斥锁;
  • 二判:进行幂等性判断,可以基于状态机、业务流水表、数据库唯一索引等,进行重复操作的判断;
  • 三更新:对数据进行更新,将数据进行持久化;

方案:

  1 请求唯一ID + 数据库唯一索引约束

    • 原理:客户端在请求下单接口的时候,调用后端获取唯一请求ID: requestId,下单时带上这个ID ,服务端拿这个请求ID,去数据库判断是否重复请求;
    • 场景:低并发,1w 以内,无法满足 10W 并发;

2 Redis 分布式锁 + 请求唯一ID

    • 原理:客户端在请求下单接口的时候,调用后端获取唯一请求ID(后端把这个ID保存在 Redis),下单时带上这个ID ,服务端对请求ID加锁 ,如果成功加锁走后续流程,如果失败提示服务在处理重复提交;
    • 场景:可满足 10W 并发;

3 Redis 分布式锁 + Token

    • 原理:不用去后端请求唯一ID,服务端根据特定规则生成 token 存入 Redis,服务端对 token 加锁,如果成功加锁走后续流程,如果失败提示服务在处理重复提交;
    • 生成规则:应用名 + 接口名 + 方法名 + 请求参数签名(请求header、body参数,取SHA1值);

 

三、如何设计秒杀系统?

 

posted @ 2025-08-06 09:58  幻月hah  阅读(9)  评论(0)    收藏  举报