Redis Sorted Sets 实现跨境电商业务订单抢占库存

历史逻辑是:收到订单,过风控Check…,查库存,占库存,有货就下发到物流渠道;否则就处于缺货的等待状态。

这么简单的流程我就不画图示意了。

这种模式,有一个弊端:假如有热卖的产品一直“爆单”,而库存不足的话,会导致先进来的订单一直卡在缺货。

原本一来货,它就应该满足库存标准,按照订单应发数量占住库存,然后下发的。这一直被后来的订单抢走了库存!

所以问题的解决结果可以明确为:先来的订单需要抢占SKU库存,后来的订单sku缺货就排队等待。

我们小组拉个会议室,对着白板,边画边展开一番解决方案讨论。一开始Leader 提议使用小顶堆。新订单进来,重新进行堆排序。让最早的订单排在小顶堆堆顶。

但是我对用Go实现一个切合当前业务的小顶堆,有点耗时间。然后我一想,这个缺货的判断你要一直持久判断,用小顶堆,持久性你怎么保存?而产品又只给了2天的开发时间,测试一天,然后就要发版。我直接说,还不如用 Redis Sorted Sets 来实现。

大家你一句,我一句。一致同意了这个大方向的技术方案。

具体到详细的方案执行上,把订单的创建时间作为有序集合成员的分值score,将订单号加上一个专属的前缀拼接成具有清晰表意的 member 值。再给一个特殊的字符串作为集合的 Key 值。这样数据结构的设计明确下来。

具体调用的业务逻辑,新单生成,进行库存查询时,先根据订单创建时间作为 max score 值,判断一下这个有序集合是不是有 member。

如果有,那就将当前订单也加入到有序集合里来。

如果没有,那么说明前面没有更早的缺货订单,就直接查库存。

查库存结果,有两种结果。若是发现有缺货,那么也还加入缺货有序集合,如果有货直接占用库存,紧接着发到物流渠道。

另外一种场景就是,采购或者订单已占用库存的订单作废,释放库存出来。这个时候相当于库存有增加,那么可以通过另一个队列触发这个来货的 sku 队列,走一样的逻辑去遍历缺货的订单 Zset,按照不缺货的先创建的订单占用库存。

当然实际业务,要比这个要复杂的多。这里只是隐匿了诸多具体业务,抽取核心技术实现点进行说明。

这样,无论怎么来订单,库存怎么变化,最后,占用库存的流转开关都交给了 Redis Sorted Sets 把控。保证了先创建的订单先占库存。


跨境电商商户也就不用担心一些爆款产品热卖,先下的缺货订单因临时库存不足,迟迟未发货遭客户投诉而被 Paypal 等支付平台冻结资金了。