php利用redis实现秒杀
使用Redis实现PHP秒杀系统
Redis的高性能和原子性操作使其成为实现秒杀系统的理想选择。以下是基于Redis的PHP秒杀解决方案:
数据结构设计
使用Redis的Hash结构存储商品库存和已售数量:
$redis->hSet('seckill_goods', 'item_id_123', 100); // 初始库存
$redis->hSet('seckill_sold', 'item_id_123', 0); // 初始已售
原子性操作实现
利用Redis的Lua脚本保证原子性:
local key = KEYS[1]
local sold_key = KEYS[2]
local user_id = ARGV[1]
local max_stock = tonumber(redis.call('HGET', key, 'stock'))
local current_sold = tonumber(redis.call('HGET', sold_key, 'sold'))
if current_sold < max_stock then
redis.call('HINCRBY', sold_key, 'sold', 1)
redis.call('SADD', 'seckill_success:'..key, user_id)
return 1
end
return 0
PHP调用示例
$script = <<<LUA
-- 上述Lua脚本内容
LUA;
$result = $redis->eval($script, [
'seckill_goods:item_id_123',
'seckill_sold:item_id_123',
$user_id
], 2);
防刷策略
-
使用Redis计数器限制用户请求频率:
$key = "user_limit:$user_id"; if ($redis->incr($key) > 5) { die('请求过于频繁'); } $redis->expire($key, 10); -
预减库存避免超卖:
$stock = $redis->hIncrBy('seckill_goods', 'item_id_123', -1); if ($stock < 0) { $redis->hIncrBy('seckill_goods', 'item_id_123', 1); // 回滚 die('已售罄'); }
异步处理订单
使用Redis队列处理实际订单创建:
$redis->rPush('order_queue', json_encode([
'user_id' => $user_id,
'item_id' => 'item_id_123',
'time' => time()
]));
系统优化建议
- 商品数据预热:活动开始前将商品数据加载到Redis
- 分布式锁:解决集群环境下的并发问题
- 库存分段:将库存分成多个段减少争抢
- 多级缓存:结合本地缓存减轻Redis压力
完整流程示例
// 1. 验证用户资格
if ($redis->sIsMember('blacklist', $user_id)) {
die('黑名单用户');
}
// 2. 频率限制
$requestKey = "user_request:$user_id";
if ($redis->incr($requestKey) > 10) {
die('请求过多');
}
// 3. 执行秒杀
$script = "..."; // Lua脚本
$result = $redis->eval($script, [$goodsKey, $soldKey, $user_id], 2);
// 4. 处理结果
if ($result) {
$orderData = [...];
$redis->rPush('order_queue', json_encode($orderData));
echo '秒杀成功';
} else {
echo '秒杀失败';
}






