php 实现秒杀功能
秒杀功能的核心设计要点
高并发场景下秒杀功能需解决超卖、性能瓶颈、公平性等问题。PHP实现需结合缓存、队列、数据库锁等机制。
基于Redis的原子操作方案
利用Redis的原子性操作实现库存扣减,避免超卖:
$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
end
return 0
LUA;
$result = $redis->eval($lua, ['seckill_stock'], 1);
if ($result) {
// 生成订单
} else {
// 已售罄
}
预减库存+异步下单
前端展示的库存数量可大于实际库存,通过异步处理降低数据库压力:
// 预减Redis库存
$remain = $redis->decr('pre_stock');
if ($remain >= 0) {
// 写入消息队列
$queue->push(['user_id' => $userId, 'item_id' => $itemId]);
echo '排队中';
} else {
$redis->incr('pre_stock'); // 恢复预减
echo '已售罄';
}
数据库最终一致性
通过队列处理实际下单过程:
// 消费者处理队列
while ($task = $queue->pop()) {
$pdo->beginTransaction();
try {
$stmt = $pdo->prepare("SELECT stock FROM items WHERE id = ? FOR UPDATE");
$stmt->execute([$task['item_id']]);
$stock = $stmt->fetchColumn();
if ($stock > 0) {
$pdo->prepare("UPDATE items SET stock = stock - 1 WHERE id = ?")->execute([$task['item_id']]);
// 创建订单
$pdo->commit();
} else {
$pdo->rollBack();
// 记录失败
}
} catch (Exception $e) {
$pdo->rollBack();
}
}
限流与防刷措施
使用Redis实现令牌桶限流:

$rateLimitKey = 'user_limit_' . $userId;
$limit = 10; // 每秒允许次数
$current = $redis->get($rateLimitKey);
if ($current && $current >= $limit) {
die('操作过于频繁');
}
$redis->multi()
->incr($rateLimitKey)
->expire($rateLimitKey, 1)
->exec();
性能优化建议
- 静态资源与动态接口分离部署
- 使用OPCache加速PHP执行
- 数据库字段添加适当索引
- 采用连接池减少MySQL连接开销
- 热点数据预加载到Redis
数据一致性保障
- 记录操作日志便于核对
- 定时任务补偿异常订单
- 库存预警机制设置阈值
- 独立计数器记录实际销量
以上方案需根据实际业务场景调整参数和实现细节,测试阶段建议使用压力测试工具验证系统承载能力。






