订单超时关闭业务场景实现
常见的交易系统中都存在这样的业务场景,用户下单之后(扣减库存,有的是在支付之后扣减库存),等待用户支付,这时如用户超过业务设置的支付时间之后,订单自动关闭,释放订单占用的资源(库存,用户优惠券,),这种业务场景下该怎么处理呢
定时任务
这种是最简单,最易处理的办法,直接使用定时任务,在订单生成是根据业务配置同步生成超时时间保存在订单表,启动一个定时任务,定时扫描订单表,已过超时时间未支付的数据,关闭订单,
优点
- 处理简单,快速上线,适合订单量不大,实时性要求不高的场景
缺点
- 性能差,如果订单数据很大,对数据库性能会有影响
- 实时性差,会存在订单已超时,未及时处理的情况
延时队列,延时任务
java自带的延迟队列DelayQueue 、ScheduleExecutor线程池,适用于业务量小,实时性要求较高的场景
优点
- 实时性好,任务超时之后会立马执行
缺点
- 无论是延时队列或延时执行的定时任务,都是把数据放在内存中,系统停止,会丢失任务数据,重启需要考虑初始化问题,而且若任务堆积过多,占用系统内存(可以考虑队列数据存放在缓存中reids等)
时间轮算法实现
时间轮算法,kafka,neety,dubbo基本上都使用这种方式实现(HashedWheelTimer ),
参考:https://www.jianshu.com/p/0f0fec47a0ad
优缺点同上面差不多
redis key过期时间监听
使用reidis ,把订单号作为key,存放在redis中,设置过期时间为订单超时的时间,应用订阅redis key的过期事件,收到过期事件通知处理
otify-keyspace-events Ex
优点
- 实时性好,数据存放redis中,对应用无影响
缺点
- redis 中key过多,订阅者需要识别key的类型
RabbitMQ 死信队列
基于rabbitMQ的死信队列实现,rabbitMQ 发送消息时,可以设置消息的过期时间,在超过过期时间,而消息未被消费时,消息将被被转移到死信队列中,也可以配置参数x-dead-letter-exchange 将死信消息转发到别的队列进行消费
缺点
- 需要配置多个消息队列,消息过期、消息队列达到最大长度or消息被消费端拒绝 消息都会被变成死信,消费端需要区分
在我们公司实际的业务场景中刚开始使用的是 定时任务,业务快速上线,开发速度快,实现简单当时数据量不大,而且我们对应的是B端的订单,超时时间是一周以上,实时性要求不高,随着订单表数据量的增大(190W),而且有其他业务场景的定时任务也在扫描订单表,下一步考虑使用redis key过期时间监听的方式实现