微软一面:订单超时未支付,如何自动关闭?

简介: 本文探讨了微软面试中关于订单超时自动关闭的设计题,提供了四种解决方案:定时器轮询、被动关闭、MQ延时消息及分布式超时中心。每种方案均详细阐述了实现思路、优缺点及适用场景。强调架构应基于业务需求,而非盲目追求高大上。适合不同规模的企业参考选用。

hi,你好,我是猿java

最近,有小伙伴私信反馈微软一面的系统设计题:订单超时未支付,如何自动关闭?

说实话,微软能问出这种面试题确实很诧异,难道是互联网人已经大量涌进了微软这个养老基地,开始卷它?言归正传,有网购经验的小伙伴应该知道,如果订单在规定的时间内没有支付,订单就会被系统自动关闭,作为技术人员,该如何设计这个功能,今天我们来分析 4种有概括性的方案。

说明:

  • 规定的时间:即超时时间,这个因平台而异,有的场景是 10分钟超时,比如 12306 购票,有的平台是 15分钟或者 30分钟超时,有些秒杀场景是 1分钟超时,具体超时值需要根据具体的业务来定。

  • 自动关闭的原因:对于有库存的业务,需要释放库存,否则容易导致少卖。比如有些用户恶意下单,不支付。

方案1: 定时器

定时器应该是我们最可能想到的方案,通过定时器去数据库轮询待支付的订单信息,然后在业务代码中判断订单是否超时,更新订单状态。

实现思路

下单的时候把超时需要关闭订单的具体时间值(pay_expire_time)保存到表里,给pay_expire_time字段添加一个索引,然后设置一个定时器,每 3s/5s 去数据库查询一次数据,查询 SQL 如下:

select id from order where order_status = '待支付' && pay_expire_time > now()

优点

定时器方案最大的优点就是实现简单

缺点

  1. 需要定时从数据库拉取数据,对数据库会产生一定的压力
  2. 需要将数据加载到内存中进行业务逻辑处理,如果拉取的数据量比较大,可能会消耗过多的内存导致OOM
  3. 定时器是周期性的,对于超时订单的关闭可能存在延时

适用场景

适用于数据量比较小的业务场景,比如,很多小公司在业务处于 0-1 的过程中,该方案比较常见。

方案2: 被动关闭

服务器不做订单的主动关闭,而是在客户端拉取订单时按需被动关闭订单,比如,客户端通过接口获取服务器的时间以及订单超时时间,然后计算并判断订单是否超时,如果超时,将订单显示成超时的样式,
并隐式向服务器发送一个订单超时关闭的请求,服务器再做相应的逻辑处理。

优点

  • 实现简单
  • 按需处理订单超时,客户端需要用到数据再做判断

缺点

  • 订单长时间未关闭,在业务意义上可能是脏数据
  • 客户端需要做超时的逻辑判断并且发送超时关闭请求

适用场景

适用于数据量比较小的业务场景,被动关闭通常会结合定时器方案使用。

方案3: MQ延时消息

有些 MQ有延时消息的特性,比如阿里开源的 RocketMQ,用户创建订单时,同时往 MQ中发送一条延时消息,用户支付成功后,删除对应的延时消息(开源版本的没有此功能),
当消费者消费到消息时再做超时的相关处理

优点

  • 利用中间件 MQ的特性,避免业务端自己实现

缺点

  • 如果使用开源的 Apache RocketMQ 4.x版本,消息延时只有特定的 18个级别,所以业务的超时时间要和 RocketMQ的延时级别相匹配才能使用
  • 强依赖中间件 MQ,所以 MQ的稳定性以及是否丢消息直接影响该功能
  • 使用开源版的 RocketMQ,没有删除延时消息的功能,因此需要对每条消息都做超时判断,增加了很多无效的数据处理
  • 如果数据量比较大,MQ可能会堆积产生延时

注意:

在 RocketMQ 4.x中 只有 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h 18个固定Level的延迟时间

在 RocketMQ 5.x,支持任意时间的延迟消息,官方解决的 issue

适用场景

适用于搭建了 RocketMQ的公司,想利用 RocketMQ的延时消息来实现该功能

方案4: 超时中心

很多大厂都有自己的分布式超时系统 TOC(Timeout Coordinator System),不同的公司可能叫法不一样,这里给出一种实现思路:

实现思路

1. 订单创建

  • 用户通过前端下单,请求发送到OMS(Order Management System)订单管理系统
  • OMS创建订单,并将订单状态设置为“待支付”或类似的初始状态

2. 注册超时事件

  • 在订单创建的同时,OMS向 TOC注册一个超时事件
  • 超时事件包含了订单ID、超时时间(例如30分钟)和超时后需要执行的动作(例如关闭订单)

3. 超时监控

  • TOC系统开始监控这个订单的超时事件
  • 如果在设定的超时时间内,用户完成了支付,OMS会更新订单状态并通知 TOC取消超时事件

4. 超时处理

  • 如果超时时间到达,而订单状态仍然是“待支付”,TOC将触发超时动作
  • TOC通知 OMS订单已超时

5. 订单关闭

  • OMS收到 OTC超时通知后,执行订单关闭操作
  • OMS将订单状态更新为“已关闭”或“超时关闭”

6. 超时后处理

  • OMS可能需要处理一些后续任务,如释放库存、退还优惠券等
  • 完成这些操作后,该订单的超时处理流程结束

优点

  • 专门的人做专门的事,性能,稳定性,扩展性有保障
  • 可以处理海量数据

缺点

  • 实现和维护成本比较高
  • 实现复杂度比较高,方案中可能会涉及分布式调度,MQ等技术栈

适用场景

适合数据量比较大的中大型公司,需要专门的团队负责

如何选择?

架构领域有句经典的台词:没有最好的架构,只有够用的架构。

这个理论用于订单超时关闭场景同样适用,分布式超时中心方案看起来高大上,而且能处理海量数据,但是,如果把这套方案用于几个人的团队,有一种杀鸡用牛刀的架势,可能不但解决不了问题,还会给团队带来技术难题和成本负担。

因此,架构一定要基于业务,方案也一定要基于业务。

对于定时器方法,看起来简单粗暴,但是很多公司的业务在 0-1的过程中,它就是首选,因为实现的成本很低,没有什么技术难点,
假设每条订单的数据大小是 1K,5万条订单的数据大概在 50M左右,用定时器把数据加载到内存中处理也是ok的,所以该方案适合每天的订单量在万级别,或者再保守一些,每日订单总量在 1万以下。

对于 MQ延时消息方案,首先需要考虑自建 MQ 还是购买 MQ云产品,以及两种方案带来的技术难点或者购买成本,基于先有 MQ这个条件再看它适合的业务场景,在根据每日的订单量是百万级别,十万级别还是万级别来选择 MQ的配置。

分布式超时中心方案技术难度和维护成本都比较高,一般适合一些独角兽企业,大厂或者财力和技术能力都不错的公司。

总结

本文分了具有概括性的 4种订单超时关闭方案,可能每个公司实现的细节或者叫法略有差异,但是思想是相通的。

通过本文,我们可以根据不同的业务体量给出不同的方案或者设计思路,以及各个方案的优缺点,具体细节可以结合具体业务细节。

没有最好的架构,只有够用(适合)的架构,很多时候在选择方案的时候一定要结合实际业务,切勿过度设计,但是也不能缺乏设计的能力

交流学习

如果文章存在缺点和错误,欢迎批评指正。更多干货和面试经,关注:猿java。

相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
支付系统39----支付宝支付,定时查单,每隔30秒执行1次,查询超过5分钟,并且未支付的订单
支付系统39----支付宝支付,定时查单,每隔30秒执行1次,查询超过5分钟,并且未支付的订单
|
20小时前
|
消息中间件 NoSQL Java
订单出现超时未关闭场景解决方案
订单出现超时未关闭场景解决方案
支付系统40------定时查单-订单未创建,支付宝登陆前在支付宝端创建还是没有创建,不知道,之所以打印警告日志,是因为创建的时候更容易看到它
支付系统40------定时查单-订单未创建,支付宝登陆前在支付宝端创建还是没有创建,不知道,之所以打印警告日志,是因为创建的时候更容易看到它
|
5月前
|
消息中间件 NoSQL Kafka
订单超时取消的11种方式(非常详细清楚)
订单超时取消的11种方式(非常详细清楚)
2478 1
订单超时取消的11种方式(非常详细清楚)
支付系统42----支付宝支付-定时查单-订单已支付,如果我们在定时查单的状态中,我们明明已经支付的订单,却在本地状态中显示没有支付,这是因我们的异步通知因为种种原因没有接受到,支付宝端成功,本地失败
支付系统42----支付宝支付-定时查单-订单已支付,如果我们在定时查单的状态中,我们明明已经支付的订单,却在本地状态中显示没有支付,这是因我们的异步通知因为种种原因没有接受到,支付宝端成功,本地失败
支付系统34----支付成功异步通知,处理重复通知,我们在我们程序当中找到处理订单的processOrder方法,我们要在更新订单状态和记录日志之前,先处理重复通知
支付系统34----支付成功异步通知,处理重复通知,我们在我们程序当中找到处理订单的processOrder方法,我们要在更新订单状态和记录日志之前,先处理重复通知
|
3月前
|
JSON 数据格式
支付系统41----定时查单-订单未支付
支付系统41----定时查单-订单未支付
|
10月前
|
消息中间件 NoSQL Java
订单超时取消的11种方法(上)
大家好,我是三友~~ 延迟任务在我们日常生活中比较常见,比如订单支付超时取消订单功能,又比如自动确定收货的功能等等。 所以本篇文章就来从实现到原理来盘点延迟任务的11种实现方式,这些方式并没有绝对的好坏之分,只是适用场景
订单超时取消的11种方法(上)
|
10月前
|
NoSQL Java 调度
订单超时取消的11种方法(下)
大家好,我是三友~~ 延迟任务在我们日常生活中比较常见,比如订单支付超时取消订单功能,又比如自动确定收货的功能等等。 所以本篇文章就来从实现到原理来盘点延迟任务的11种实现方式,这些方式并没有绝对的好坏之分,只是适用场景的不大相同。
订单超时取消的11种方法(下)
|
消息中间件 NoSQL 数据库
订单超时未支付自动取消--实现简述
订单超时未支付自动取消--实现简述
222 0