php实现秒杀
秒杀系统核心设计要点
高并发、超卖问题和系统稳定性是秒杀系统的核心挑战。PHP实现需结合缓存、队列、数据库锁等技术。
缓存预热与静态化
将秒杀商品信息提前加载到Redis缓存,避免活动开始后直接查询数据库。商品详情页可生成静态HTML,减少动态请求压力。
// Redis预热示例
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->set('seckill_item_123', json_encode([
'stock' => 1000,
'price' => 99
]));
原子库存控制
使用Redis的原子操作保证库存扣减的准确性,避免超卖。Lua脚本保证操作的原子性。

$lua = <<<LUA
local stock = tonumber(redis.call('GET', KEYS[1]))
if stock <= 0 then
return 0
end
redis.call('DECR', KEYS[1])
return 1
LUA;
$result = $redis->eval($lua, ['seckill_item_123'], 1);
消息队列削峰
将秒杀请求放入RabbitMQ或Kafka队列,后端Worker异步处理订单创建,避免瞬时高峰压垮数据库。
// RabbitMQ生产者示例
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('seckill_orders', false, true, false, false);
$msg = new AMQPMessage(json_encode([
'user_id' => 123,
'item_id' => 456
]));
$channel->basic_publish($msg, '', 'seckill_orders');
限流与熔断
使用Nginx层限流或PHP代码限制用户请求频率。令牌桶算法控制整体QPS。

// 令牌桶限流示例
$rateLimiter = new TokenBucket(1000, 1000); // 容量1000,速率1000/秒
if (!$rateLimiter->consume(1)) {
header('HTTP/1.1 429 Too Many Requests');
exit;
}
分布式锁控制
多服务器环境下使用Redis分布式锁,避免重复处理同一请求。
$lockKey = 'seckill_lock_123';
$lock = $redis->set($lockKey, 1, ['NX', 'EX' => 10]);
if (!$lock) {
// 获取锁失败
return false;
}
数据分片与降级
对秒杀数据按商品ID分片存储。准备降级策略,如活动过于火爆时展示排队页面。
事后校验
最终通过数据库事务确保数据一致性,对Redis预扣减结果进行最终确认。
// 数据库事务示例
$pdo->beginTransaction();
try {
$stmt = $pdo->prepare("UPDATE items SET stock = stock - 1 WHERE id = ? AND stock > 0");
$stmt->execute([$itemId]);
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
// 补偿Redis库存
}






