场景——订单
一、订单超时的解决方案
描述:购物下单后没有付款。系统超时30分钟自动关闭订单。
方案:
| 方案 | 场景 | 优点 | 缺点 |
| JDK 自带的延时队列 | 小型单机应用,非核心业务 |
实现简单,基于 JDK 自带 API,无需额外组件; |
仅适用于单机环境,不支持分布式; 数据在内存中 DelayQueue,服务重启后,队列中的任务会丢失; 无法应对大量订单场景,容易造成内存溢出。 |
| Redis 的过期监听 | 中小规模分布式应用,对时效性要求不高的场景 |
实现相对简单,利用 Redis 的过期机制; 支持分布式,可在多节点部署监听; 无需复杂的任务调度逻辑 |
Redis 的过期删除并非实时,存在延迟;(定期删除、惰性删除) 监听机制可能存在消息丢失风险; 当过期键数量较多时,可能影响 Redis 性能。 |
| 常用★★★基于 MQ 的延时消息 | 中大规模分布式应用,核心业务,对可靠性和时效性要求较高 |
可靠性高,支持消息持久化,服务重启后消息不丢失; 时效性较好,不同 MQ 能提供不同精度的延时; 支持分布式,可扩展性强; 能应对高并发场景 |
需要引入 MQ 组件,增加了系统复杂度; 部分 MQ 的延时消息功能需要额外配置或开发; 可能存在一定的消息投递延迟 |
| 常用★★★分布式定时任务批处理 | 大规模分布式应用,对时效性要求不高,订单量极大的场景 |
支持分布式,能有效应对海量订单; 可靠性高,可通过任务重试机制保证处理结果; 可根据业务需求灵活设置调度周期 |
实现复杂,需要搭建分布式定时任务框架; 时效性较差,依赖任务调度周期,可能存在订单超时后一段时间才被处理的情况; 批量处理时,若处理逻辑复杂,可能影响性能 |
1 RabbitMQ 的延时消息:
- 业务发送一个延时消息,我们把消息写入到对应的队列。
- 可以设置队列的 TTL(存活时间),当消息超时后,进入死信交换机。
- 定义一个 BizQueue 用来接收死信消息,进行业务的消费。
优点:
-
- 可以支持海量延时消息,支持分布式处理。
缺点:
-
- 不灵活,只能支持固定延时等级;
- 使用复杂,要配置一堆延时队列;
2 RocketMQ 的定时消息:
- 业务发送一个定时消息。
- 到了时间,RocketMQ 会通知客户端去处理。(时间轮算法)
优点:
-
- 使用简单,和使用普通消息一样。
- 支持分布式。
- 精度高,支持任意时刻。
缺点:
-
- 定时时长最大值 24 小时。
- 成本高:每个订单需要新增一个定时消息,且不会马上消费,给MQ带来很大的存储成本。
- 同一个时刻大量消息会导致消息延迟:定时消息的实现逻辑需要先经过定时存储等待触发,定时时间到达后才会被投递给消费者。因此,如果将大量定时消息的定时时间设置为同一时刻,则到达该时刻后会有大量消息同时需要被处理,会造成系统压力过大,导致消息分发延迟,影响定时精度。
3 (推荐)定时任务分布式批处理:
利用 SchedulerX 的分布式调度能力,定期(如每 1 分钟)触发任务,批量扫描数据库中 “已创建但未支付且已超时” 的订单,执行关闭操作(更新状态、释放库存等)。
关键组建:
实现流程:
- 任务配置:在 SchedulerX 控制台创建定时任务;
- 分片逻辑实现:执行器接收到任务后,根据分片索引拆分订单 ID 范围,避免重复处理;
- 可靠性保障:失败重试(自定义配置)、幂等性处理、监控告警(任务失败或超时)
二、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值);
三、如何设计秒杀系统?

浙公网安备 33010602011771号