背景引入:
对于秒杀、抽奖这类问题,在高并发库存扣减时,可能会产生超卖问题。
解决思路:使用redis来解决。
对数据库的修改时,数据库会加行级锁,在高并发场景下对库存进行修改。会导致大量的用户线程处于等待状态。为了解决这个问题,我们可以使用redis+MQ。首先redis是基于内存,读写时非常快的,在高并发的场景下,我们可以首先对redis进行库存扣减,之后通过MQ的延时队列来同步MySQL,保持redis和MySQL数据之间的一致性。
实现方案:
使用redis的decr命令,decr可以将库存值每次减少1。由于decr命令是具有原子性的,可以保证在高并发的场景下进行库存的扣减。并且使用decr命令会返回扣减后的值,我们可以对该值进行加锁setnx,用于防止由于网络波动、或者库存恢复进行重复扣减问题。redis扣减完成后,会发送一条MQ消息到延迟队列中,通过定义一个定时任务去延迟队列中拉取消息,这样就可以降低MySQL的压力解决超卖问题。
可能会存在的隐患:如果redis挂掉了如何解决?
redis挂了会有主从切换,如果真都大面积挂了,没办法。只能降级。
redis如果整个都挂掉了,如果并发量没那么大可以降级使用MySQL。但是在大厂并发量较高的情况下,MySQL处理不了那么多的请求,这时只能将服务下线。
面试官又问:如果此时主节点的数据还没有及时的同步到从节点
此时,我们的实现方案是做了两层的防护的。比如说:主节点的库存已经扣减到了50,此时从节点的库存还有55,那么从节点切换到主节点进行库存扣减时,使用decr命令还会返回50-54的数值,此时我们再次setnx加锁时会加锁失败,导致库存扣减失败。 如果大部分的redis都挂了,那么我们只能对此接口进行降级操作。提示用户活动暂时下线或者路由到其他的页面。
抽奖会有大量的请求,库存扣减使用的是redis+MQ,但是每次中奖记录也要存入到MySQL中,这个时候会产生问题吗?
插入数据不会产生锁竞争,不是update更新热点数据。