应通过系统层限制CPU和内存:用systemd-run或service设CPUQuota,queue.php配memory阈值,supervisor中用php -d指定memory_limit,Redis队列需避免序列化失败并拆分大任务。

队列任务里 CPU 占满怎么办
Laravel 本身不提供 CPU 使用率限制机制,php artisan queue:work 启动的进程一旦执行耗 CPU 的任务(比如图像处理、大数组排序、递归解析),就会吃光单核资源,影响同服务器其他 PHP 进程响应。这不是 Laravel 的 bug,是 PHP 进程天然没资源隔离。
实操上只能靠系统层控制:用 cgroups(Linux v2)或 systemd --scope 给队列 worker 进程划资源上限。例如限制 CPU 使用不超过 50%:
systemd-run --scope -p CPUQuota=50% php artisan queue:work
注意:systemd-run 是临时方案,生产环境建议写成 systemd service 文件,并配 Restart=always;别用 cpulimit,它对多线程 PHP 不稳定,常导致 worker 挂死。
内存爆掉后队列直接卡死
Laravel 队列任务默认无内存上限,ini_set('memory_limit', '-1') 或配置文件里设为 -1 是常见错误操作——这等于把内存保险丝拔了。一旦某个任务泄露内存(比如循环中不断 array_merge 大数组、未释放 GD 图像资源),worker 进程会 OOM 被 kernel 杀掉,且不会重试,消息就丢了。
必须做两件事:
- 在
config/queue.php的options里加'memory' => 128(单位 MB),这是php artisan queue:work内置的内存检查阈值,超限自动重启 worker - 在任务逻辑开头加
gc_enable(),并在循环体末尾手动gc_collect_cycles(),尤其处理大量对象或 PDO 结果集时 - 避免在任务中用
file_get_contents读大文件,改用fopen + stream_get_line流式处理
supervisor 管理下 memory_limit 不生效
很多人在 supervisord.conf 里写了 environment=PHP_MEMORY_LIMIT="128M",却发现 memory_limit 没被继承——因为 supervisor 的 environment 只影响 shell 环境变量,不透传给 PHP 的 ini 设置。
正确做法只有两个:
- 在
supervisord.conf的 command 行显式指定:command=php -d memory_limit=128M /var/www/artisan queue:work - 或者统一在
php.ini里设memory_limit = 128M,但要确认 CLI SAPI 加载的是这个配置(运行php --ini看路径)
别信网上“改 php-fpm.conf 就行”的说法,队列走的是 CLI,跟 FPM 完全无关。
Redis 队列里任务堆积但 CPU/内存都空闲
看起来资源充足,但 php artisan queue:work 处理极慢,甚至卡住,大概率是 Redis 连接阻塞或序列化问题。Laravel 默认用 serialize() 存任务,如果任务里含 Closure、resource 或未实现 __serialize() 的对象,反序列化失败会导致 silent fail,任务永远卡在 reserved 状态。
排查和修复建议:
- 用
redis-cli monitor看实际发到 Redis 的命令,确认lpush和rpop是否正常交互 - 换
redis驱动为phpredis扩展(而非predis),后者在高并发下序列化兼容性更稳 - 所有任务类必须实现
ShouldQueue,且构造参数只传基本类型或 Eloquent 模型(模型会被自动转为 ID 重载,避免序列化失败)
真正麻烦的不是限制资源,而是让任务本身不依赖无限资源——比如把一个 500MB 的 Excel 导入拆成每 1000 行一个子任务,比硬调 memory_limit 管用十倍。











