1. 问题描述
在线商城是目前电商领域最受欢迎的业态之一。然而,在高并发场景下,就必须考虑到库存监控、订单监控、并发库存控制等问题。
其中库存管控是电商平台中最重要的一环,而 Redis 也是在线商城中最受欢迎的存储技术之一。不过,在采用 Redis 进行库存监控时,会面临超卖的问题,这是目前在线商城平台中最常见的问题之一。
2. Redis库存超卖问题
Redis 是一款高性能、非关系型的内存数据库。其将数据缓存在内存中,因此具有快速访问、处理速度高等优点。在电商场景中,我们可以使用 Redis 存储在线购物的商品信息、用户信息和订单信息等,同时还可以使用 Redis 实现高性能的库存监控。
但是,Redis 监控库存时存在一个致命问题——超卖。造成超卖的原因是 Redis 不支持事务的一致性,且使用 Redis 递减命令 DECR 的时候,当库存为 0 时,会持续递减。
2.1 超卖的原因
Redis 的递减就是让两个操作同时共存,通过判断满足条件就会执行,由于这种并发特性,当并发情况下,还剩最后一件商品时,会出现多个请求同时执行 DECR 操作,造成大量的超卖情况。
2.2 超卖的危害
当出现超卖现象时,最直接的影响就是会造成库存数量跟实际销售量不符,严重的会导致商品无法售卖,销售利润的下降,同时也会破坏商家的信誉。
3. Redis库存监控解决方案
目前,在 Redis 库存控制方面,市面上诞生了很多解决方案。下面介绍几种比较常用的解决方案:
3.1 乐观锁
事务在进行之前先假定不会有冲突,只有在提交时才会与当前数据进行比对,如果没有冲突则提交,如果有冲突就回滚整个操作,再重新进行一次操作。
在 Redis 中,乐观锁可以通过 CAS 命令来实现:
WATCH key # 监视 key 的值
while True:
INITIAL = GET key
Desired = calculate_change(INITIAL)
MULTI # 事务开始
SETNX key : Sentinel
current = GET key
if ( current == Sentinel || current == INITIAL ):
SET key : Desired
EXEC
该方案利用了 Redis 的 WATCH 命令,通过设置条件变量,如果一个资源没有被修改,就会一直循环监视,直到资源被修改或操作超时。
3.2 悲观锁
事务在进行之前默认假定有冲突,需要对数据进行加锁,最终处理完毕之后再进行释放。
在 Redis 中,悲观锁可以通过 SETNX 和 EXPIRE 命令来实现:
SETNX key value # 如果 key 存在就返回 0 ,如果不存在返回 1
EXPIRE key 3 # 设置超时时间
该方案利用了 Redis 的 EXPIRE 命令,通过设置超时时间来释放锁,避免了锁无法释放的情况。
3.3 数量预加载
在进行库存控制时,需要对库存和订单的并发进行考虑。可以通过使用一定的策略,例如每个 Redis 实例仅负责一定数量的商品,降低 Redis 实例之间的竞争。
另外,我们可以根据实际情况,预加载一定数量的商品进入 Redis 实例中,避免库存瞬间减为 0 的情况:
INCRBY key count # 通过 INCRBY 命令一次性把数量写入 Redis
4. 总结
在在线商城电商平台中,Redis 是一种非常常用的高性能存储技术,而在使用 Redis 监控库存时,我们需要注意由于无法实现事务级别的一致性导致的超卖问题。对于这个问题,我们可以采用乐观锁、悲观锁和数量预加载等多种处理方案来解决。在使用这些方案之前,需要对自己的业务进行分析,并根据实际情况选择最适合自己的处理方案,提高系统的性能和稳定性。