Menu Home

利用 Redis 解决秒杀超卖问题

前段时间做了一个秒杀的功能,利用redis的高性能和事务特性,用于解决高并发情况下商品库存扣减,预防商品超卖的问题。

扣减库存的过程,主要用到了redis的watchmultiexec等命令。

watch 命令用于监视一个或多个key,监视事务执行过程key是否有被其他命令修改,如果key有被修改,事务将被打断,事务中涉及的修改会被回滚。

multi 命令用于开始事务。

exec 命令用于执行事务,如果事务执行成功,返回命令的执行结果;如果事务被中断,返回false。

 /*
 * 秒杀扣减库存
 */
 function reduceStock($userId, $productId)
 {
 // 初始化redis
 $redis = …
 // 商品库存key
 $stockKey = 'seckill:' . $productId . 'stock:';
 $stock    = $redis->get($stockKey);
 if ($stock <= 0) { 
     // 商品库存小于等于0,商品已被抢完
     return false;
 }
 $memberKey = 'seckill:' . $productId . ':uid:' . $userId;
 if ($redis->sIsMember($memberKey)) { 
     // 该用户已参与过该商品本次秒杀活动
     return false;
 }
 // 使用watch命令监视一个或多个key
 // 如果在事务执行之前,被监视的key如果又被其他命令修改
 // 那么事务将被打断,事务中涉及的修改会被回滚
 $redis->watch($stockKey);
 // 调用命令multi开始事务
 $redis->multi();
 $redis->decr($stockKey); // 减库存
 $redis->sAdd($memberKey, $userId); // 将用户加入已参见活动的集合
 // 调用命令exec执行事务
 $result = $redis->exec();
 $redis->close(); // 关闭redis连接
 if (!$result) {
     // 执行事务失败,扣减库存失败
     return false;
 }
 // 执行事务失败,扣减库存成功
 return true;
 } 

Categories: PHP

Tagged as:

muzi