php利用redis实现秒杀
PHP 利用 Redis 实现秒杀功能
秒杀场景的核心在于解决高并发下的超卖和性能问题。Redis 凭借其单线程原子性和高性能特性,是理想的解决方案之一。以下是具体实现方案:
使用 Redis 计数器 + Lua 脚本
Redis 的原子操作可确保计数准确性,Lua 脚本保证操作序列的原子性。
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// Lua 脚本(检查库存并扣减)
$lua = <<<LUA
local stock = tonumber(redis.call('GET', KEYS[1]))
if stock > 0 then
redis.call('DECR', KEYS[1])
return 1
else
return 0
end
LUA;
$result = $redis->eval($lua, ['seckill_item_123'], 1);
if ($result) {
// 秒杀成功,进入订单处理队列
} else {
// 库存不足
}
预减库存 + 异步下单
-
初始化库存

redis-cli SET seckill_item_123 100 # 设置库存为100 -
PHP 预减逻辑
$stock = $redis->decr('seckill_item_123'); if ($stock >= 0) { // 生成唯一订单ID $orderId = uniqid('seckill_'); // 异步写入订单队列 $redis->lPush('seckill_orders', json_encode([ 'order_id' => $orderId, 'item_id' => 'item_123', 'user_id' => $userId ])); } else { $redis->incr('seckill_item_123'); // 恢复库存 }
防止重复抢购
利用 Redis 的 Set 结构记录已抢购用户:

$key = "seckill_users:item_123";
if (!$redis->sIsMember($key, $userId)) {
$redis->sAdd($key, $userId);
// 继续处理秒杀逻辑
} else {
die("每人限购1件");
}
完整流程设计
-
预热阶段
- 将商品库存加载到 Redis
- 设置库存键:
SET seckill:stock_123 1000
-
秒杀阶段
- 用户请求先经过 Lua 脚本原子扣减
- 成功后将订单数据推入 RabbitMQ/Kafka
-
异步处理
- 消费队列生成正式订单
- 失败时通过定时任务恢复库存
注意事项
- 库存回滚:异步下单失败时需要恢复 Redis 库存
- 限流措施:结合 Redis 的
INCR实现接口限流 - 集群扩展:Redis Cluster 模式下需确保 Lua 脚本的键在相同节点
通过以上方案,PHP 应用可实现 10,000+ QPS 的秒杀处理能力,关键点在于所有库存操作必须在 Redis 内存中完成,避免直接访问数据库。






