php抢购实现
PHP抢购系统实现要点
抢购系统需要解决高并发、库存超卖、系统稳定性等问题。以下是实现抢购功能的关键技术点:
数据库设计
创建商品表和订单表,商品表需包含库存字段并设置乐观锁或悲观锁。例如:
CREATE TABLE `product` (
`id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
`stock` int(11) NOT NULL COMMENT '库存',
`version` int(11) NOT NULL DEFAULT 0 COMMENT '乐观锁版本号'
);
乐观锁实现
使用版本号控制并发更新,SQL语句示例:
$pdo->beginTransaction();
$stmt = $pdo->prepare("SELECT stock, version FROM product WHERE id = ? FOR UPDATE");
$stmt->execute([$productId]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
if ($product['stock'] > 0) {
$update = $pdo->prepare("UPDATE product SET stock = stock - 1, version = version + 1
WHERE id = ? AND version = ?");
$affected = $update->execute([$productId, $product['version']]);
if ($affected) {
// 创建订单
$pdo->commit();
} else {
$pdo->rollBack();
}
}
限流措施
使用Redis实现计数器限流:
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'product_' . $productId;
$limit = 1000; // 每秒限流数
if ($redis->incr($key) > $limit) {
die('活动太火爆,请稍后再试');
}
$redis->expire($key, 1); // 1秒过期
队列消峰
将请求放入消息队列异步处理:
// 使用Redis列表作为队列
$redis->lPush('seckill_queue', json_encode([
'user_id' => $userId,
'product_id' => $productId,
'time' => time()
]));
缓存预热
活动开始前将库存加载到Redis:
$stock = 1000; // 从数据库获取的实际库存
$redis->set('product_stock_' . $productId, $stock);
原子性操作
使用Redis的DECR和Lua脚本保证原子性:
local stock = tonumber(redis.call('GET', KEYS[1]))
if stock > 0 then
redis.call('DECR', KEYS[1])
return 1
end
return 0
PHP调用示例:
$script = "上面Lua脚本内容";
$sha = $redis->script('load', $script);
$result = $redis->evalSha($sha, ['product_stock_' . $productId], 1);
系统优化建议
前端实现按钮防重复点击和倒计时控制 采用CDN加速静态资源加载 使用Nginx负载均衡分散请求压力 数据库读写分离,主库处理写请求 实施服务降级策略保证核心流程
注意事项
实际部署时需要压力测试验证系统承载能力 建立完善的监控系统实时发现性能瓶颈 考虑分布式锁解决集群环境下的同步问题 记录详细日志便于问题排查和数据分析







