对于抢购这种容易出现库存超卖和系统变慢的场景,传统的做法是直接依赖数据库处理,但一旦遇到高并发请求,数据库很容易就被拖垮。想解决这个问题,我们得换个思路,把“扣库存”这一关键动作移到缓存里来执行。接下来详细说说具体是怎么操作的。 第一步是初始化库存。系统启动时,我们要一次性把商品的库存数量读入到Redis里,直接在内存中保存起来。这样一来,后续所有的库存扣减操作都能在内存里完成,完全不用再去抢数据库锁。 第二步是处理抢购请求。当客户端发起秒杀请求时,服务端首先会通过Redis的decrement命令去预减库存。如果减完后返回的库存数量大于0,说明还有货,我们就把这个请求扔进消息队列里;如果减到0或者负数了,直接返回秒杀失败,后面的数据库操作就可以跳过了。这一步就彻底杜绝了超卖的可能性。 第三步是处理消息队列里的请求。因为刚才我们把请求扔进了队列里,所以这个队列(这里用Redis自带的List来模拟)会慢慢消费这些请求。每处理一个请求,都会去数据库再次扣减库存、生成订单并且落库。 这个Demo咱们用Spring Boot和Redis来快速搭建。首先在启动类里初始化库存,通过@PostConstruct注解和opsForValue().set方法把库存数据存进去。接着用Redis的List来做消息队列,生产者用LPUSH把请求压进去,消费者用BRPOP把请求拉出来。 我们还需要一个高并发抢购的接口来模拟点击。这个接口里用ExecutorService开1万个线程去执行抢购动作。接口的逻辑是先用opsForValue().decrement去减库存,减完后判断还有没有货,如果有就用opsForList().rightPush把UUID字符串压入队列返回成功;没货就直接返回卖光了。 最后用压测工具跑1万次请求验证效果。结果发现后台只记录到了10条落库订单,其他全部都被Redis的decrement卡死了。这就证明咱们的防超卖方案确实有效。 总的来说就是三步:缓存前置处理库存、预减库存后再入队、异步落库处理订单。只要把这三板斧跑顺了,就能在大流量的冲击下稳住阵脚。