php 实现抢购
抢购系统设计要点
抢购系统需要解决高并发、库存超卖、系统稳定性等问题。以下是PHP实现抢购的核心方案:
数据库设计
创建商品表和订单表,商品表需包含库存字段并设置乐观锁:
CREATE TABLE `product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`stock` int(11) NOT NULL COMMENT '库存',
`version` int(11) NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (`id`)
);
CREATE TABLE `order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
乐观锁实现
通过版本号控制并发更新:
$pdo->beginTransaction();
try {
// 查询商品信息并锁定行
$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 = ?"
);
$update->execute([$productId, $product['version']]);
if ($update->rowCount() > 0) {
// 创建订单
$pdo->prepare("INSERT INTO `order` (product_id, user_id) VALUES (?, ?)")
->execute([$productId, $userId]);
$pdo->commit();
return true;
}
}
$pdo->rollBack();
return false;
} catch (Exception $e) {
$pdo->rollBack();
throw $e;
}
缓存预热
使用Redis预存商品库存,避免直接穿透到数据库:

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 活动开始前初始化库存
$redis->set("product_stock_{$productId}", 100);
原子计数器
通过Redis的原子操作保证库存扣减:
$remaining = $redis->decr("product_stock_{$productId}");
if ($remaining >= 0) {
// 进入订单创建流程
} else {
// 库存不足
$redis->incr("product_stock_{$productId}"); // 回滚
}
限流措施
使用Redis实现令牌桶限流:

$rateLimitKey = "rate_limit_{$productId}";
$limit = 100; // 每秒100个请求
if ($redis->exists($rateLimitKey)) {
$current = $redis->incr($rateLimitKey);
if ($current > $limit) {
http_response_code(429);
exit('Too many requests');
}
} else {
$redis->setex($rateLimitKey, 1, 1);
}
异步处理
将订单创建放入消息队列缓解压力:
// 使用RabbitMQ
$connection = new AMQPConnection(['host' => '127.0.0.1']);
$channel = $connection->channel();
$channel->queue_declare('order_queue', false, true, false, false);
$msg = new AMQPMessage(json_encode([
'product_id' => $productId,
'user_id' => $userId
]));
$channel->basic_publish($msg, '', 'order_queue');
防机器人脚本
添加验证码机制:
session_start();
if ($_POST['captcha'] !== $_SESSION['captcha']) {
die('验证码错误');
}
系统监控
实现实时监控关键指标:
// 使用Prometheus客户端
$gauge = new Gauge('seckill_requests_total', 'Total requests');
$gauge->inc(); // 请求计数
以上方案需根据实际业务场景调整,测试阶段应进行压力测试验证系统承载能力。分布式环境需考虑使用分布式锁替代单机锁方案。






