php利用redis实现秒杀
PHP 利用 Redis 实现秒杀功能
秒杀场景的特点是高并发、低库存,Redis 因其高性能和原子性操作,成为实现秒杀系统的理想工具。以下是核心实现方法:
使用 Redis 原子操作控制库存
通过 Redis 的 DECR 或 INCRBY 命令原子性扣减库存,避免超卖问题。

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 初始化库存(例如100件)
$redis->set('seckill_stock', 100);
// 用户请求秒杀时
$remaining = $redis->decr('seckill_stock');
if ($remaining >= 0) {
// 库存充足,生成订单
$orderId = createOrder();
echo "秒杀成功,订单ID: $orderId";
} else {
// 库存不足
$redis->incr('seckill_stock'); // 回滚库存
echo "秒杀失败,库存不足";
}
利用 Lua 脚本保证操作原子性
复杂逻辑可通过 Lua 脚本确保多个操作的原子性,避免竞态条件。

$luaScript = <<<LUA
local stockKey = KEYS[1]
local userId = ARGV[1]
local stock = tonumber(redis.call('GET', stockKey))
if stock > 0 then
redis.call('DECR', stockKey)
return 'SUCCESS'
else
return 'FAILED'
end
LUA;
$result = $redis->eval($luaScript, ['seckill_stock'], [uniqid()]);
if ($result === 'SUCCESS') {
// 处理订单逻辑
}
限流与防刷机制
-
IP/用户限流:使用 Redis 计数器限制单个用户的请求频率。
$key = 'seckill_limit:' . $userIp; if ($redis->incr($key) > 5) { die("请求过于频繁"); } $redis->expire($key, 10); // 10秒内限流 -
队列削峰:将请求放入 Redis 队列,后台异步处理。
$redis->lPush('seckill_queue', json_encode(['user_id' => 123, 'time' => time()]));
数据预热与库存分离
- 预热库存:活动开始前将商品库存加载到 Redis。
- 库存分离:实际库存与 Redis 库存分开管理,通过定时同步避免差异。
注意事项
- Redis 持久化:配置 AOF 或 RDB 防止数据丢失。
- 集群部署:高并发场景需使用 Redis 集群。
- 兜底方案:数据库最终一致性校验,避免 Redis 故障导致数据错误。
通过以上方法,可高效实现秒杀功能,兼顾性能与数据一致性。






