php秒杀功能的实现
实现秒杀功能的核心要点
高并发场景下秒杀功能需要解决超卖、数据库压力、用户体验等问题。以下是关键实现方案:
数据库设计优化
创建独立的秒杀表,减少主表压力:
CREATE TABLE `seckill` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`product_id` bigint(20) NOT NULL,
`stock` int(11) NOT NULL,
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_time` (`start_time`,`end_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
使用乐观锁避免超卖:
UPDATE seckill SET stock = stock - 1
WHERE product_id = 123 AND stock > 0
缓存层设计
采用Redis预减库存:
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 初始化库存
$redis->set('seckill:123:stock', 100);
// 原子性减库存
$remaining = $redis->decr('seckill:123:stock');
if ($remaining >= 0) {
// 进入下单流程
}
使用Redis队列防止重复请求:

$requestId = md5($userId . $productId);
if ($redis->setnx("seckill:request:$requestId", 1)) {
$redis->expire("seckill:request:$requestId", 10);
// 处理请求
}
流量控制策略
实现令牌桶限流算法:
class TokenBucket {
private $capacity;
private $tokens;
private $lastTime;
public function __construct($capacity) {
$this->capacity = $capacity;
$this->tokens = $capacity;
$this->lastTime = time();
}
public function consume() {
$now = time();
$this->tokens = min($this->capacity,
$this->tokens + ($now - $this->lastTime));
$this->lastTime = $now;
if ($this->tokens >= 1) {
$this->tokens -= 1;
return true;
}
return false;
}
}
异步处理订单
使用消息队列解耦:
// 生产者
$rabbitmq = new AMQPConnection();
$channel = $rabbitmq->channel();
$channel->queue_declare('seckill_orders', false, true, false, false);
$msg = new AMQPMessage(json_encode([
'user_id' => $userId,
'product_id' => $productId
]));
$channel->basic_publish($msg, '', 'seckill_orders');
// 消费者
$callback = function ($msg) {
// 处理订单落库
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};
$channel->basic_consume('seckill_orders', '', false, false, false, false, $callback);
前端优化方案
采用倒计时同步策略:

function syncServerTime() {
return fetch('/api/server_time')
.then(res => res.json())
.then(data => {
const serverTime = new Date(data.time);
const localTime = new Date();
return serverTime - localTime;
});
}
按钮状态控制:
document.getElementById('seckill-btn').addEventListener('click', function() {
this.disabled = true;
fetch('/seckill', { method: 'POST' })
.then(response => response.json())
.then(data => {
alert(data.message);
});
});
服务降级方案
配置降级开关:
if ($config['degrade']) {
header('HTTP/1.1 503 Service Unavailable');
exit('系统繁忙,请稍后再试');
}
静态化兜底页面:
if ($redis->get('seckill:123:stock') <= 0) {
readfile('/path/to/static/sold_out.html');
exit;
}
以上方案组合使用可构建完整的秒杀系统,实际部署时需要根据业务规模调整各环节参数,并进行充分的压力测试。






