如何为Laravel应用配置高效的队列系统? (Redis与Supervisor实战)

10次阅读

laravel队列卡在pending状态主因是未启用真实驱动(如redis)且配置未生效;需改QUEUE_CONNECTION、清缓存、用queue:work配合Supervisor常驻运行,并避免序列化大对象或连接未复用。

如何为Laravel应用配置高效的队列系统? (Redis与Supervisor实战)

为什么 Laravel 队列卡在 pending 状态不执行?

绝大多数情况不是代码写错了,而是队列驱动没真正跑起来。Laravel 默认用 sync 驱动,它根本不会进队列,直接同步执行——这会让你误以为“队列在工作”,实际只是假象。

必须显式切换到真实驱动,比如 redis,并在 .env 中确认:

QUEUE_CONNECTION=redis REDIS_HOST=127.0.0.1 REDIS_PORT=6379

别漏掉 php artisan config:clear,Laravel 会缓存配置,改了 .env 不清缓存等于白改。

常见错误现象:

  • 执行 dispatch(new SendEmailJob()) 后,php artisan queue:work 没任何输出,数据库 jobs 表为空(说明根本没走数据库驱动)
  • Redis 里有 queues:default 列表,但 queue:work 进程启动后立刻退出或无响应(多半是 Redis 连接失败或权限问题)

用 Supervisor 管理 queue:work 进程的最小可行配置

Supervisor 不是可选工具,是生产环境必须项。手动敲 php artisan queue:work 一旦终端断开或报错就停,任务直接积压。

关键点不在“怎么写配置”,而在“怎么验证它真在跑”:

  • command 必须带 --sleep=3--max-jobs=1000,防止内存泄漏和无限重试拖垮进程
  • autostart=trueautorestart=true 是基础,但必须加 startsecs=5,否则 Supervisor 可能误判进程启动失败
  • 日志路径建议用绝对路径,比如 /var/log/supervisor/laravel-queue.log,避免权限或路径解析问题

一个精简但可用的 /etc/supervisor/conf.d/laravel-queue.conf

[program:laravel-queue] process_name=%(program_name)s_%(process_num)02d command=php /var/www/myapp/artisan queue:work redis --sleep=3 --max-jobs=1000 --max-time=3600 autostart=true autorestart=true startsecs=5 user=www-data numprocs=2 redirect_stderr=true stdout_logfile=/var/log/supervisor/laravel-queue.log

配完别忘了:supervisorctl reread && supervisorctl update && supervisorctl start laravel-queue:*

queue:workqueue:listen 到底该用哪个?

答案很明确:只用 queue:work,彻底忘掉 queue:listen

queue:listen 是 Laravel 5.2 之前的遗留命令,它靠轮询 + include 重新加载代码,每次任务都重新启动整个 Laravel 应用上下文,内存占用高、启动慢、热更新不可靠,官方早已弃用。

queue:work 是常驻进程,复用应用实例,性能好得多,但代价是——代码变更后必须重启进程才能生效。这就是为什么 Supervisor 的 autorestart 要配合部署脚本使用:

  • 部署新代码后,运行 supervisorctl restart laravel-queue:*
  • 或者用 php artisan queue:restart 触发优雅重启(它只是往 Redis 写个信号,queue:work 进程自己监听并退出)

别指望修改了 Job 类就自动生效,不重启进程,旧代码一直跑着。

Redis 队列延迟高?先检查这三件事

不是 Redis 不行,而是 Laravel 默认配置太“保守”。延迟高往往卡在连接池或序列化环节:

  • redis 连接配置里没开 pconnect(持久连接),每次取任务都新建 TCP 连接,耗时翻倍。在 config/database.phpredis 部分加 'options' => ['prefix' => 'laravel_database_'] 不够,要确认 Redis 扩展支持 phpredis 并启用 pconnect
  • Job 类用了大对象(比如整个 Request 实例)作为构造参数,序列化成 jsON 后体积暴涨,Redis 读写变慢。应只传 ID 或必要字段,用 __construct($userId) 而非 __construct(Request $request)
  • 没设置 --max-time=3600,单个任务超时后被强制 kill,Supervisor 立刻拉起新进程,反复 fork 导致系统负载飙升,间接拖慢其他任务

验证是否真卡 Redis:在 queue:work 命令后加 --verbose,看每条日志的时间戳间隔。如果“popping”和“processing”之间差几百毫秒,基本就是连接或序列化问题。

text=ZqhQzanResources