本文使用的库存数量模型
本文为了描述方便,我们使用简化的库存数量模型,真实使用实际的库存数量项可根据实际需要设计。
库存数量表-stockNum
字段名 |
英文名 |
字段类型 |
商品标识 |
skuId |
长整型 |
库存数量 |
num |
整数 |
传统通过数据库保证不超卖
通过Sql里判断剩余的库存数够用,多个并发执行update语句只有一个能执行成功。
Update stockNum set num=num-下单数量 where skuId=商品ID and num-下单数量>0
本方法并不是本文重点,使用数据库做数量扣减,面临高并发就没有办法进行抗量,我们接下来设计一种使用Redis缓存做库存扣减的方案。
PS:分库分表并不能根本解决库存扣减的高并发,因为分库分表是按商品,促销的时候高并发都是针对少量商品的,甚至是一个商品,最终并发流量会打向少数表,分库分表会起不到作用,只能去提升单分片的并发能力。
Redis做扣减的原理
扣减库存其实包含两部分,第一部分超卖校验,第二部分最终扣减掉库存;在传统数据库扣减中,两部是一起完成的,同时完成了超卖校验(where中的判断)和扣减(update 数量);如果我们想解决这两部分,就需要把两个问题分开解决:
第一关解决超卖检验:我们可以把数据放入Redis中,每次扣减库存,都对Redis中的数据进行incryby 扣减,如果返回的数量大于0,说明库存够,因为Redis是单线程,可以信任返回结果。第一关是Redis,可以抗高并发,性能Ok。超卖校验通过后,进入第二关。
第二关解决库存扣减:经过第一关后,第二关不需要再判断数量是否足够,只需要傻瓜扣减库存就行,对数据库执行如下语句:
Update stockNum set num=num-下单数量 where skuId=商品ID
疑问来了,此处因为数据库是按商品分库分表,并发量又没有减少,问题不是没有解决吗?是的,还需要引入一个重量级武器,任务库,我们并不直接在业务库上执行上面的扣减语句,我们只在任务库记录这个扣减任务,再异步进行扣减就可以。任务库使用订单号或其他可以散列开的字段进行分库分表,这样针对同一个商品的不同订单会散列在任务库的不同库存,虽然还是数据库抗量,但已经消除了数据库热点。
整体架构如下:
数量校验和数据持久化分开了,Redis缓存负责校验数量,异步任务负责数据持久化。
在后续文章中,我会对任务库的设计进行介绍,任务库不仅仅可以做数据的最终一致性,也可以作为状态机引擎支撑起状态机,服务于状态机业务。
本文地址:https://blog.csdn.net/qrycf/article/details/110495295