秒杀场景的特点是短时间、高并发,业务系统要处理瞬时的大量高并发请求,而Redis
的高性能特性就经常被用来支撑秒杀活动。
根据我们的购物体验,我们可以把秒杀场景分为三个阶段,第一个阶段是秒杀前,我们
一般都会在活动开始前就进到页面刷新,这时候我们的商品详情页面的流量会激增,
所以我们通常会把这个页面静态化,通过浏览器缓存或者cdn把静态页面缓存起来,
以此来缓解服务端压力。
第二个阶段是活动开始的时候,会有大量请求到达服务端,先是查询库存,库存足够,
扣减库存,下单进而订单处理,如果库存不够则返回。压力最大的时候是查询库存的
时候,通常会使用redis来进行库存的查询及库存扣减操作,并不会在数据库端做库存扣减操
作,首先因为数据库相较而言比较慢,而且还得进行数据库与redis的数据同步,容易因为
数据更新慢而导致商品超卖情况,查询库存及库存扣减操作,必须保证其原子性。
第三个阶段是订单后续处理,物流、供应链、退单等等情况,这个阶段是请求量较小,
普通服务端基本能满足。
高并发
商品秒杀是典型的高并发场景,redis本身的特性足以满足并发要求,需要注意的是,如果
商品较多的情况下,我们可以把这些商品分布在不同的切片实例上,避免秒杀请求集中在
少量实例上,我们需事先通过crc计算好各商品的key对应的slot,然后合理的把slot分配
到实例上。
查询库存及扣减库存的原子性
我们必须保证查询库存及扣减库存在同一请求下的原子性执行,不然库存就乱套了,我们
可以之间使用redis的原子性操作,因为查询库存和扣减库存是两条命令,所以我们得依赖
lua脚本以完成原子性操作。
另一个方案则是通过分布式锁来保证多客户端的互斥性,请求会先访问锁的实例,得到
锁之后,再执行后续查询库存及扣减库存操作,建议把锁和库存放在不同实例上。