php结合Redis实现高并发下的秒杀抢购功能

实现思路

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

代码部分

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


// 秒杀开始前,将库存放入redis队列中

include_once dirname(__FILE__) . '/RedisUtil.php';

$config = array(
'host' => '127.0.0.1', // redis 服务器地址
'port' => 10001, // redis 服务器端口号
'timeOut' => 10, // redis 客户端连接超时时间
'password' => '123456' // redis 客户端连接密码
);
$redisUtil = new RedisUtil($config);

// 假设秒杀总库存为500
$stock = 500;

// 待秒杀的商品编号
$goodsId = 1000001;

// 将商品库存依次放入队列中
for ($i=0; $i<$stock; $i++) {
$redisUtil->setLeftList('stock_'.$goodsId,1);
}
    buy.php 模拟秒杀抢购


// 模拟秒杀

include_once dirname(__FILE__) . '/RedisUtil.php';

$config = array(
'host' => '127.0.0.1', // redis 服务器地址
'port' => 10001, // redis 服务器端口号
'timeOut' => 10, // redis 客户端连接超时时间
'password' => '123456' // redis 客户端连接密码
);
$redisUtil = new RedisUtil($config);

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

$users = 10000;

// 待秒杀的商品编号
$goodsId = 1000001;


// 从队列左侧弹出一个元素,如果有值,说明还有剩余库存
$rs = $redisUtil->popLeft('stock_'.$goodsId);
$num = sprintf('%05s', $i);
if (!$rs) {
echo '售罄了!用户'.$num;
echo '<br/>';
// 输出最终抢购成功的用户数量
echo '最终抢购人数:'.$redisUtil->getListSize('users').' 人';
echo '<br/>';
echo '<br/>';
return;
} else {
// 将抢购成功的用户存入队列
$redisUtil->setLeftList('users',$num);
echo '恭喜您!用户'.$num;
}

 

redis的所有方法都具有原子性,高并发下,也是一条一条执行的。但是,如果2个方法一起使用的话,则无法保证原子性。所以只能使用list类型的popLeft方法,可以避免高并发下的超卖

posted on   lansedongqing  阅读(885)  评论(0编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示