应通过调整 --sleep 参数、启用 --daemon 模式、配置 redis block_for、自定义轻量监听器及限制 --max-jobs/--max-time 来降低 laravel 队列 cpu 占用。

如果您在运行 Laravel 队列工作进程时观察到 CPU 占用率持续偏高,即使队列为空也频繁出现峰值,则很可能是由于工作进程在空闲时轮询过于密集。默认的 queue:work 命令在无任务时会以极短间隔反复检查队列,每次检查均需加载 Laravel 框架上下文,造成大量重复开销。以下是优化队列睡眠间隔以显著降低 CPU 占用的具体方法:
一、使用 --sleep 参数调整空闲等待时间
该参数直接控制工作进程在未获取到新任务时的休眠时长,避免高频轮询。增大此值可线性减少每分钟框架加载次数,从而大幅缓解 CPU 压力。
1、停止当前正在运行的队列进程(如通过 supervisorctl stop laravel-queue)。
2、修改 Supervisor 配置文件中 command 行,添加 --sleep=5 参数,例如:php /var/www/project/artisan queue:work redis --sleep=5 --queue=high,default。
3、保存配置后执行 sudo supervisorctl reread && sudo supervisorctl update 重载配置。
4、重启队列进程:sudo supervisorctl start laravel-queue:*。
二、启用 --daemon 模式配合 --sleep 实现框架单次加载
--daemon 模式使工作进程在启动时一次性加载整个 Laravel 应用框架,并在后续所有任务处理及空闲等待中复用该实例,彻底消除每次轮询时的框架初始化开销。
1、确认 Laravel 版本为 4.2 或更高(Laravel 5.0+ 默认支持,且推荐使用)。
2、在 Supervisor 的 command 中同时指定 --daemon 和 --sleep=3,例如:php /var/www/project/artisan queue:work redis --daemon --sleep=3 --tries=3。
3、确保部署流程中包含 supervisorctl restart laravel-queue:* 步骤,以在代码更新后强制重启守护进程。
4、验证进程是否以守护模式运行:执行 ps aux | grep 'queue:work' | grep daemon,应可见对应进程存在。
三、切换至阻塞式队列驱动(Redis block_for)
对于 Redis 驱动,可通过启用阻塞读取机制替代轮询。当队列为空时,Redis 客户端将挂起连接直至有新任务入队或超时,完全消除空转 CPU 消耗。
1、打开 config/queue.php 文件,定位到 redis 驱动配置项。
2、在 'redis' => [...] 数组内添加或修改字段:'block_for' => 5。
3、确保队列命令不带 --sleep 参数(因阻塞逻辑已接管等待行为),例如仅运行:php artisan queue:work redis --queue=high,default。
4、确认 Redis 服务端未启用 notify-keyspace-events 冲突配置,以免干扰阻塞操作。
四、自定义轻量监听器替代 Artisan Worker
当上述标准方案仍无法满足严苛 CPU 限制(如低配 VPS)时,可绕过 Artisan 全栈加载,用原生 PHP + Pheanstalk 或 PhpRedis 编写极简监听器,仅解析任务并按需触发独立 Artisan 命令。
1、创建独立脚本 app/Console/CustomQueueListener.php,使用 Pheanstalk::reserve(5) 或 Redis::brpop() 实现阻塞等待。
2、解析取出的 JSON 任务数据,提取类名与参数。
3、通过 proc_open() 调用 php artisan app:handle-job {class} {data} 执行具体逻辑,子进程结束后自动释放资源。
4、将该脚本交由 Supervisor 管理,command 设为 php /var/www/project/app/Console/CustomQueueListener.php。
五、结合 --max-jobs 与 --max-time 实施进程生命周期控制
即使启用 --daemon,长时间运行的进程仍可能因内存泄漏或数据库连接失效导致隐性资源占用上升。通过限制单个进程处理任务数或运行时长,可强制其周期性退出并由 Supervisor 重启,维持稳定 CPU 占用水平。
1、在 Supervisor 的 command 行中加入 --max-jobs=250 和 --max-time=3600 参数。
2、确保 --max-time 值小于系统级超时限制(如 systemd 的 TimeoutSec 或 Supervisor 的 stopwaitsecs)。
3、设置 Supervisor 的 autorestart=true 和 startretries=3,保障进程退出后立即拉起新实例。
4、监控日志中是否出现 "Maximum job limit reached" 或 "Maximum time limit reached" 提示,确认机制生效。











