php队列实现抢购
PHP队列实现抢购方案
抢购场景下高并发容易导致超卖、数据库崩溃等问题。使用队列系统能有效缓解压力,以下是基于PHP的常见实现方案:
使用Redis队列
Redis的List结构适合作为轻量级队列,处理抢购请求:
// 初始化Redis连接
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 抢购请求入队
$productId = 1001;
$userId = mt_rand(1000,9999);
$redis->lPush('seckill_queue', json_encode(['user_id'=>$userId, 'product_id'=>$productId]));
// 后台进程消费队列
while(true) {
$data = $redis->rPop('seckill_queue');
if($data) {
$order = json_decode($data, true);
processOrder($order['user_id'], $order['product_id']);
}
usleep(100000); // 0.1秒间隔
}
数据库事务+乐观锁
队列处理后端配合数据库保证数据一致性:
function processOrder($userId, $productId) {
$pdo->beginTransaction();
try {
// 查询库存(加锁)
$stmt = $pdo->prepare("SELECT stock FROM products WHERE id=? FOR UPDATE");
$stmt->execute([$productId]);
$stock = $stmt->fetchColumn();
if($stock > 0) {
// 减库存
$pdo->prepare("UPDATE products SET stock=stock-1 WHERE id=?")->execute([$productId]);
// 创建订单
$pdo->prepare("INSERT INTO orders(...) VALUES(...)")->execute([...]);
$pdo->commit();
return true;
}
$pdo->rollBack();
return false;
} catch(Exception $e) {
$pdo->rollBack();
return false;
}
}
使用专业队列系统
对于大规模抢购,建议采用专业队列服务:
- RabbitMQ方案
// 生产者 $connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest'); $channel = $connection->channel(); $channel->queue_declare('seckill', false, true, false, false); $msg = new AMQPMessage(json_encode($orderData)); $channel->basic_publish($msg, '', 'seckill');
// 消费者 $callback = function($msg) { processOrder(json_decode($msg->body, true)); $msg->ack(); }; $channel->basic_consume('seckill', '', false, false, false, false, $callback);
2. Kafka方案
```php
$producer = new RdKafka\Producer();
$producer->addBrokers("kafka:9092");
$topic = $producer->newTopic("seckill");
$topic->produce(RD_KAFKA_PARTITION_UA, 0, json_encode($orderData));
预减库存+异步确认
前端展示与实际库存分离的方案:
// 使用Redis原子操作预减库存
$redis->watch('seckill_stock');
$stock = $redis->get('seckill_stock');
if($stock > 0) {
$redis->multi();
$redis->decr('seckill_stock');
$redis->lPush('seckill_queue', $orderData);
$redis->exec();
echo '抢购排队中';
} else {
echo '已售罄';
}
防刷策略
结合队列需要增加安全措施:
- 用户频率限制(Redis计数器)
- 验证码验证
- 排队进度查询接口
- 订单超时释放库存
这种架构将瞬时高峰请求转为异步处理,数据库压力降低90%以上。实际部署时需要根据业务规模选择合适队列方案,配合负载均衡和多节点部署。







