08.支付超时


延迟任务(不推荐)

  1. 下单时增加一个定时任务,在五分钟后对订单进行超时判断。
  2. 超时判断时,可以先去支付宝上查询订单支付状态。

如果已支付,则判断订单是否正常结束,这是因为在用户完成扫码支付后,支付宝正常会往图灵电商发送支付成功的通知。但是这个通知是没有事务保证的,所以是非常有可能失败的,这时就需要在订单超时判断时对状态进行对齐。
如果未支付,则需要释放库存,取消本地订单,然后通知支付宝取消支付订单。

五分钟时间太长了,而支付宝的通知又没有事务保证,通常企业中的做法并不会等到订单超时时才去查询订单状态,而是在后台会多次频繁查询支付宝支付状态,这样可以更及时的获得支付结果。例如五分钟超时时间,至少需要半分钟或者一分钟去查一次支付宝订单状态,如果支付成功了,就及时结束后续等待处理过程。如果没有完成支付,就再开启下一个定时任务,等待下次检查。

RocketMQ事务消息(推荐)

RocketMQ事务消息机制的核心是对消息状态进行不断的确认。循环确认的过程就正好可以用来改造,解决上面说的频繁任务调度的问题。这样就可以专注于开发业务逻辑,而不用关注频繁复杂的任务调度逻辑。

  1. 支付宝预下单时发送事务消息:通知下游服务进行订单取消
  2. 发送消息后,会先执行本地事务。
    • 将订单ID放到Redis中,这样可以在后续进行支付状态检查时,快速找到对应的业务信息。
    • 只要下单成功,就会返回UNKOWN状态,这样RocketMQ会在之后进行状态回查(检查支付宝支付状态)。
  3. 然后在事务状态回查时
    • 会自行记录回查次数,超过最大次数就直接取消订单(transactionCheckInterval,默认回查15次,间隔60s,超过ROLLBACK
      • 如果没有超过最大次数,就可以去支付宝中查询订单支付状态。
        • 如果已经支付完成,则返回ROLLBACK状态,消息取消,后续就不会再进行本地订单取消了。
        • 如果未支付,则记录回查次数后,返回UNKNOWN状态,等待下次回查。
  4. 如果订单已经超时(事务消息成功发送出去了)
    • 下游的消费者就会完成取消本地订单,释放库存等操作。
  5. 如果本地订单已经取消,而支付宝支付状态已经成功,则退款

通过聚合支付进行分布式事务控制

如果在对接过程中,直接使用支付宝的二维码通知用户进行当面支付。而用户使用支付宝扫码支付的过程,电商都是完全不知道的,也就没有办法对用户的支付动作进行控制。比如如果电商本地的订单已经超时,就要阻止用户进行扫码支付。可以在支付宝的回调接口判断订单状态,如果订单式已关闭,则发起订单回退。这样显然效率是不高的。

在很多电商项目中,会采用聚合支付的方式,统一对接多个第三方支付方。用户的支付动作就不是直接与支付宝这样的第三方支付公司交互完成,而是要经过电商后台转发请求完成。这时,就可以通过添加一些分布式锁机制,保证整个支付业务是串行执行的,以防止在电商进行订单超时回退后,用户再次扫码支付

正向通知与反向通知

当前是通过事务消息通知下游服务订单取消,这其实就是一种反向通知的方式。但是其实最直观的方式还是使用正向通知,即通过事务消息通知下游服务进行订单支付确认,这样这个下单的消息就容易扩展更多的下游消费者。订单下单确认是用户完成支付后,支付宝发起的通知来确认的。这时,如果订单确认的下游服务实现了幂等控制,就完全可以将事务消息机制改为正向通知。即在事务消息回查过程中,确认用户已经完成了支付,就发送消息通知下游服务订单支付成功。这样也可以防止支付宝通知丢失造成的订单状态缺失。

而用户订单超时判断,则可以在事务消息的状态回查过程中,通过记录回查次数判断。如果已经超时,则返回Rollback。同时启动另外一个消息生产者,往下游服务发送一个订单取消的消息,这样也是可以的。

兜底补偿机制

对于订单超时后的回退处理,不光通过RocketMQ的事务消息进行了通知,另外也部署定时任务,批量回退超时的订单。
这其实就是一种事务消息的兜底补偿机制,以处理那些事务消息机制有可能漏处理的超时订单。在设计金融相关业务时,这种兜底策略会显得尤为重要。

总结梳理

延迟任务(不推荐)

RocketMQ事务消息(反向通知)

  1. 支付宝预下单时发送事务消息:通知下游服务进行订单取消

  2. 发送消息后,会先执行本地事务。

    • 将订单ID放到Redis中,这样可以在后续进行支付状态检查时,快速找到对应的业务信息。

    • 只要下单成功,就会返回UNKOWN状态,这样RocketMQ会在之后进行状态回查(检查支付宝支付状态)。

  3. 然后在事务状态回查时

    • 会自行记录回查次数,超过最大次数就直接取消订单(transactionCheckInterval,默认回查15次,间隔60s,超过ROLLBACK

      • 如果没有超过最大次数,就可以去支付宝中查询订单支付状态。

        • 如果已经支付完成,则返回ROLLBACK状态,消息取消,后续就不会再进行本地订单取消了。

        • 如果未支付,则记录回查次数后,返回UNKNOWN状态,等待下次回查。

  4. 如果订单已经超时(事务消息成功发送出去了)

    • 下游的消费者就会完成取消本地订单,释放库存等操作。
  5. 如果本地订单已经取消,而支付宝支付状态已经成功,则退款

聚合支付平台(分布式锁): 防止在电商进行订单超时回退后,用户再次扫码支付

正向通知: 需要订单确认的下游服务实现幂等控制

兜底补偿机制:定时任务批量回退超时的订单


文章作者: 钱不寒
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 钱不寒 !
  目录