针对秒杀项目,我们在处理时需要考虑到大量数据涌入的影响、兜底机制以及并发时锁的选择。
首先,对于数据的处理可以采用 Redis 进行 缓存预热 ,将需要秒杀的商品数据放入 Redis 中来应对高并发量。但引入 Redis 后,我们必须考虑 Redis 缓存与数据库的 数据一致性 问题。
并发读取以及数据一致性的考虑 :
对于并发扣减,这里我们采用乐观锁机制进行处理,因为它比较轻量,而悲观锁较重,会降低处理速度。
例如:
sql
UPDATE stock SET stock = stock - 1 WHERE stc_id = ? AND stock >= 1
看上面这个语句,首先我们使用了 SQL 的 UPDATE 是以当前读语义执行:拿到行锁后基于最新已提交版本评估WHERE,这样获取到的数据是最新的。同时通过 stc_id 选取想要扣减的商品,用 stock >= 1 作为乐观锁的处理条件,确保库存数量 ≥ 1,防止出现超卖现象。
而对于数据一致性:
我们在 Redis 中进行了扣减,面对大量数据请求可以放到消息队列里做削峰处理,通过消息队列的消费者进行数据库的扣减。同时我们需要考虑 Redis 和数据库是否一致?这里我们可以在 Redis 中利用 ZSet 的特性,存放扣减的商品,score 里记录扣减的时间,然后与数据库中的数据做对比,逐个看扣减的是否落库,如果有问题再进行相应处理,相当于一个补偿机制。
对于数据库的处理:我们可以对数据库进行分库分表的操作,将各个商品路由到不同的表中,这样能降低数据库的压力。
兜底机制 :对于兜底机制而言,如果我们的 Redis 崩了(这里说的是单机,我们也可以通过 Redis 的主从节点搭配哨兵或者 Redis 集群),我们可以直接返回给用户秒杀结束的兜底策略。
幂等性处理: 同一个用户如果恶意刷单,会占库存,这里我们可以使用给用户的订单上加上token字段,用户请求生成订单的时候,由后端生成对应的字段然后保存,加上数据库的唯一约束,就可以防止用户的多个订单。
然后也可以通过redis对用户加分布式锁,这样的话,也可以防止用户,下单时进行校验,这样的话也可以对其进行幂等处理。