准备两个队列A和B,假设A队列的名称为stock,用于存放商品总库存信息,B队列的名称为users,用于存放抢购成功后的用户信息。每当有用户进行抢购操作时,先从A队列弹出一个元素,如果该元素有值,说明还有剩余库存,此时,将用户信息存入B队列,否则,说明已无库存,应该终止抢购。

stock.php 用于设置队列中的库存信息

  1. // 秒杀开始前,将库存放入redis队列中
  2. include_once dirname(__FILE__) . '/RedisUtil.php';
  3. $config = array(
  4. 'host' => '127.0.0.1', // redis 服务器地址
  5. 'port' => 10001, // redis 服务器端口号
  6. 'timeOut' => 10, // redis 客户端连接超时时间
  7. 'password' => '123456' // redis 客户端连接密码
  8. );
  9. $redisUtil = new RedisUtil($config);
  10. // 假设秒杀总库存为500
  11. $stock = 500;
  12. // 待秒杀的商品编号
  13. $goodsId = 1000001;
  14. // 将商品库存依次放入队列中
  15. for ($i=0; $i<$stock; $i++) {
  16. $redisUtil->setLeftList('stock_'.$goodsId,1);
  17. }

buy.php 模拟秒杀抢购

  1. // 模拟秒杀
  2. include_once dirname(__FILE__) . '/RedisUtil.php';
  3. $config = array(
  4. 'host' => '127.0.0.1', // redis 服务器地址
  5. 'port' => 10001, // redis 服务器端口号
  6. 'timeOut' => 10, // redis 客户端连接超时时间
  7. 'password' => '123456' // redis 客户端连接密码
  8. );
  9. $redisUtil = new RedisUtil($config);
  10. // 此处假设有10000个用户同时来抢购商品,注意:我们的库存只有500个
  11. // 预期情况是:500个库存都被抢光,且没有出现超卖现象
  12. $users = 10000;
  13. // 待秒杀的商品编号
  14. $goodsId = 1000001;
  15. for ($i=1; $i<=$users; $i++) {
  16. // 从队列左侧弹出一个元素,如果有值,说明还有剩余库存
  17. $rs = $redisUtil->popLeft('stock_'.$goodsId);
  18. $num = sprintf('%05s', $i);
  19. if (!$rs) {
  20. echo '售罄了!用户'.$num;
  21. echo '<br/>';
  22. // 输出最终抢购成功的用户数量
  23. echo '最终抢购人数:'.$redisUtil->getListSize('users').' 人';
  24. echo '<br/>';
  25. echo '<br/>';
  26. return;
  27. } else {
  28. // 将抢购成功的用户存入队列
  29. $redisUtil->setLeftList('users',$num);
  30. echo '恭喜您!用户'.$num;
  31. }
  32. echo '<br/>';
  33. }

此处假设有10000个用户同时来抢购商品,注意:我们的库存只有500个,预期情况是:500个库存都被抢光,且没有出现超卖现象。

秒杀结果

结合Redis实现高并发下的秒杀抢购 - 图1

从截图上可以看出,正好符合我们的预期,秒杀基本完成,剩下的就是一些后续的业务逻辑处理,如:入库操作等等。