php实现秒杀
PHP实现秒杀功能的关键技术
秒杀场景需要解决高并发、超卖、系统崩溃等问题。以下是实现秒杀功能的核心方案:
数据库层面优化
使用InnoDB引擎的行级锁或乐观锁控制库存。例如通过UPDATE语句自带的行锁特性:
UPDATE products SET stock = stock - 1 WHERE id = 123 AND stock > 0
添加唯一索引防止重复购买:
ALTER TABLE orders ADD UNIQUE INDEX idx_user_product (user_id, product_id);
Redis缓存预热与原子操作
将库存数据预热到Redis中,利用DECR或INCRBY的原子性操作:
$redis->watch('stock');
$stock = $redis->get('stock');
if ($stock > 0) {
$redis->multi();
$redis->decr('stock');
$redis->exec();
} else {
$redis->unwatch();
}
使用Redis列表实现令牌桶限流:
for ($i = 0; $i < 1000; $i++) {
$redis->lpush('seckill_tokens', $i);
}
消息队列削峰填谷
用RabbitMQ或Kafka缓冲请求:
$channel->queue_declare('seckill', false, true, false, false);
$channel->basic_publish(
new AMQPMessage(json_encode(['user_id' => 1, 'product_id' => 123])),
'',
'seckill'
);
服务层优化
采用Nginx+Lua实现灰度发布和AB测试:
local redis = require "resty.redis"
local red = redis:new()
local ok, err = red:get("stock")
if tonumber(ok) > 0 then
-- 放行到PHP后端
end
使用OPcache加速PHP脚本:
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=4000
前端防护策略
静态资源CDN化,按钮添加防重复点击:
document.getElementById('seckill-btn').addEventListener('click', function() {
this.disabled = true;
// 提交请求
});
时间校验采用后端统一时间:
$serverTime = microtime(true);
if ($serverTime < $startTime || $serverTime > $endTime) {
die('活动未开始或已结束');
}
限流与熔断机制
Nginx层限流配置:
limit_req_zone $binary_remote_addr zone=seckill:10m rate=10r/s;
location /seckill {
limit_req zone=seckill burst=20;
}
PHP代码实现令牌桶算法:
class TokenBucket {
private $capacity;
private $tokens;
private $lastTime;
public function __construct($capacity) {
$this->capacity = $capacity;
$this->tokens = $capacity;
$this->lastTime = time();
}
public function consume($tokens) {
$now = time();
$this->tokens = min($this->capacity,
$this->tokens + ($now - $this->lastTime) * 10);
$this->lastTime = $now;
if ($this->tokens >= $tokens) {
$this->tokens -= $tokens;
return true;
}
return false;
}
}
数据一致性方案
采用延迟双删策略保证缓存与数据库一致:
$redis->del('product_123');
$db->query('UPDATE products SET stock = stock - 1 WHERE id = 123');
usleep(50000); // 50ms延迟
$redis->del('product_123');
压力测试建议
使用JMeter模拟并发请求时,注意设置合理的思考时间(Think Time)和阶梯式加压。典型测试参数应包含:

- 并发用户数:500-5000
- 持续时间:5-10分钟
- 响应时间目标:<500ms
- 错误率:<0.1%






