php redis实现秒杀
PHP 与 Redis 实现秒杀功能
秒杀功能的核心在于处理高并发请求,确保库存不超卖且系统稳定。Redis 因其高性能和原子性操作非常适合此类场景。
使用 Redis 原子操作保证库存
通过 Redis 的 DECR 或 INCRBY 命令实现原子性库存扣减。提前将商品库存存入 Redis,例如:
$redis->set('seckill:stock:123', 100); // 商品ID为123,库存100
扣减库存时使用原子操作:
$remaining = $redis->decr('seckill:stock:123');
if ($remaining >= 0) {
// 库存扣减成功,生成订单
} else {
// 库存不足,回滚操作
$redis->incr('seckill:stock:123');
}
使用 Redis 队列削峰
将秒杀请求先放入 Redis 队列,后台异步处理订单,避免直接冲击数据库:

$redis->lpush('seckill:queue', json_encode(['user_id' => 1, 'product_id' => 123]));
后台脚本消费队列:
while (true) {
$data = $redis->rpop('seckill:queue');
if ($data) {
$orderData = json_decode($data, true);
// 处理订单逻辑
}
}
使用 Redis 分布式锁防重复提交
通过 SETNX 实现分布式锁,防止用户重复提交:

$lockKey = 'seckill:lock:' . $userId;
$locked = $redis->setnx($lockKey, 1);
if ($locked) {
$redis->expire($lockKey, 10); // 锁10秒
// 处理秒杀逻辑
$redis->del($lockKey);
} else {
// 重复请求,直接返回
}
使用 Lua 脚本保证原子性
复杂操作可通过 Lua 脚本保证原子性执行:
$script = "
local stock = redis.call('GET', KEYS[1])
if tonumber(stock) > 0 then
redis.call('DECR', KEYS[1])
return 1
end
return 0
";
$result = $redis->eval($script, ['seckill:stock:123'], 1);
if ($result) {
// 秒杀成功
}
缓存预热与限流
提前将商品信息加载到 Redis 减少数据库压力。使用 Redis 计数器限制用户请求频率:
$key = 'seckill:rate_limit:' . $userId;
$count = $redis->incr($key);
if ($count == 1) {
$redis->expire($key, 60); // 60秒内限制
}
if ($count > 10) {
// 超过10次请求,拒绝
}
数据一致性处理
通过消息队列或定时任务同步 Redis 与数据库库存。失败时采用补偿机制:
// 订单创建成功后同步库存
if ($orderCreated) {
$db->query("UPDATE products SET stock = stock - 1 WHERE id = 123");
} else {
$redis->incr('seckill:stock:123'); // 回滚Redis库存
}
注意事项
- Redis 需要配置持久化防止数据丢失
- 采用集群模式保证高可用
- 压力测试验证系统承载能力
- 前端可增加验证码或倒计时进一步过滤请求






