跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

PHP项目高并发部署:使用Redis队列与消息中间件缓解数据库压力

PHP秒杀场景需用Redis队列解耦写请求:LPUSH入队、pconnect持久连接、LPOP消费、DECRBY或Lua原子扣库存,并用Supervisor守护进程。 PHP项目在秒杀、抢券或活动爆发时,数据库瞬间被大量写请求击穿,连接数爆满、响应超时、数据错乱,必须把耗时操作从主流程中剥离出来。 将用户请求存入Redis队列 用
LPUSH
把请求参数压入列表,不直接操作MySQL。这一步操作起来很简单,直接把用户ID、商品ID、时间戳打包成JSON字符串塞进去就行。 方法一:基础写入 创建Redis实例→调用
$redis->connect('127.0.0.1', 6379)
→执行
$redis->LPUSH('order_queue', json_encode($payload))
。注意不要用
SET
覆盖,必须用
LPUSH
保证FIFO顺序。 方法二:带错误兜底的写入 包裹
try/catch
,捕获
RedisException
;失败时记录日志并降级为本地文件队列(如
file_put_contents('/tmp/queue_fallback.log', ...)
),避免请求丢失。 【关键前提:Redis服务必须已启动且端口可通,否则整个写入链路中断】 立即学习 “ PHP免费学习笔记(深入) ”; 后台守护进程消费队列 用
LPOP
逐条取出请求,处理完再入库。不能用
BRPOP
阻塞式读取——它会让进程挂起,无法响应信号退出,线上难以管理。 第一步:建立持久连接
$redis = new Redis(); $redis->pconnect('127.0.0.1', 6379, 30);
比
connect()
省去每次TCP握手开销,尤其适合长周期运行的守护进程。 第二步:循环拉取+防空转 用
while (true)
包裹
$value = $redis->LPOP('order_queue')
;若返回
false
,立即
usleep(10000)
(10毫秒),避免CPU空转打满。这比
sleep(1)
更精细,也比无休止轮询更省资源。 第三步:解析与落库 对
$value
做
json_decode($value, true)
;校验字段完整性;拼接
INSERT INTO orders (...) VALUES (...)
;执行
mysqli_query()
后检查
mysqli_affected_rows()
是否为1。失败则记录错误详情到
/var/log/queue_consumer.err
,跳过当前条目继续下一条。 防止库存超卖的原子扣减 下单前必须校验并扣减库存,但普通SELECT+UPDATE在并发下会失效。必须用Redis原生命令保障原子性。 方法一:DECRBY配合GET判断 先
$remain = $redis->DECRBY('stock:1001', 1)
;再
if ($remain INCRBY('stock:1001', 1); return '库存不足'; }
。这三行代码必须连续执行,中间不能插入其他逻辑。 方法二:Lua脚本强一致性控制 写一段Lua脚本:
if redis.call("GET", KEYS[1]) >= ARGV[1] then redis.call("DECRBY", KEYS[1], ARGV[1]) return 1 else return 0 end
;用
$redis->eval($script, ['stock:1001'], [1])
调用。Lua在Redis单线程内执行,彻底规避竞态条件。 配置Supervisor守护消费者进程 让
php /path/to/consumer.php
常驻后台、崩溃自动重启、日志自动轮转。 编辑
/etc/supervisor/conf.d/redis-consumer.conf
,填入以下内容:
[program:redis-consumer]
command=php /var/www/app/queue/consumer.php
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/supervisor/redis-consumer.log
执行
supervisorctl reread && supervisorctl update && supervisorctl start redis-consumer
。此时进程已纳入系统级监管,
ps aux | grep consumer
能查到正在运行的PHP进程。

相关文章