php利用redis实现秒杀
Redis实现秒杀的核心思路
利用Redis的高性能和原子性操作解决高并发下的超卖问题。核心是通过Redis的DECR或INCRBY命令原子性扣减库存,配合Lua脚本保证操作完整性。
关键实现步骤
Redis预加载库存 将商品库存提前存入Redis,例如使用字符串结构:
$redis->set('seckill_good_123', 100); // 初始库存100
原子性扣减库存
使用DECR命令保证原子性操作,返回值为扣减后的值:
$remaining = $redis->decr('seckill_good_123');
if ($remaining >= 0) {
// 扣减成功,进入订单创建流程
} else {
// 库存不足,回滚操作
$redis->incr('seckill_good_123');
}
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
PHP调用示例:
$script = <<<LUA
-- 上述Lua脚本内容
LUA;
$result = $redis->eval($script, ['seckill_good_123'], 1);
防重复购买 使用Redis集合记录已购买用户:
if ($redis->sAdd('seckill_users_123', $user_id)) {
// 首次购买
} else {
// 重复请求
}
结果异步处理 扣减成功后,将订单信息推入队列:
$orderData = ['user_id' => 123, 'good_id' => 456];
$redis->lPush('seckill_order_queue', json_encode($orderData));
性能优化建议
- 使用连接池管理Redis连接
- 对商品ID进行分片存储(如
seckill_good_123_shard1) - 前置验证:先检查用户是否在限制名单内
- 采用令牌桶算法控制流量
异常处理机制
- 设置Redis操作重试机制
- 记录操作日志用于对账
- 实现库存回滚接口
- 监控Redis内存和CPU使用率
通过上述方案,Redis能在毫秒级完成库存扣减判断,配合数据库最终完成订单创建,实现万级QPS的秒杀场景。实际部署时需要根据压测结果调整Redis配置和集群方案。







