高并发下laravel队列需重点管控连接、分发、消费三环节:redis连接须手动ping验证通路;任务分发应传id而非模型实例以防序列化失败;queue:work必须由supervisor守护,禁用已废弃的--daemon模式。

高并发场景下,Laravel 队列不能只靠改 QUEUE_CONNECTION=redis 就完事。真实压测中掉链子的,90% 出在连接、分发、消费三个环节的隐性断点上。
Redis 连接必须手动验证通路,别信 .env 里写了就等于通了
很多人配完 QUEUE_CONNECTION=redis 就跑 php artisan queue:work,结果任务静默消失——根本没进 Redis。原因常是:
-
config/queue.php中redis.connection值(比如'default')和config/database.php里redis.default的键名不一致,导致 Laravel 用了一个未定义的连接配置 - 本地开了 Redis 但没启动,或生产环境
REDIS_HOST指向了内网 DNS,而队列 worker 运行在另一台无解析权限的机器上 - 用了 PhpRedis 扩展却没在
config/queue.php中显式指定'options' => ['serializer' => 'php'],Predis 和 PhpRedis 序列化不兼容,dispatch()不报错但数据写入乱码
验证方法:进 php artisan tinker,执行 Redis::ping(),返回 "PONG" 才算真正连通;再试 Redis::lpush('test', 'x') + Redis::rpop('test') 确保读写正常。
任务分发时传 ID 而非模型实例,SerializesModels 不是万能解药
高并发下最常触发内存溢出或序列化失败的,就是 SendEmailJob::dispatch($user) 这种写法。Eloquent 模型携带的 $relations、$casts、闭包访问器等,在序列化进 Redis 时会膨胀数倍,且可能直接抛 Serialization of 'Closure' is not allowed。
- 正确做法:只传主键
SendEmailJob::dispatch($user->id),在handle()中重新查库:$user = User::findOrFail($this->userId) - 如果真要传模型,必须加
use SerializesModels;,且确保构造函数里没调用$user->load('posts')这类 eager loading —— 它会把整张关联表都序列化进去 - 避免在构造函数里做任何 I/O,如
Storage::get()或Http::get(),这些操作应在handle()中执行
queue:work 必须由 supervisor 守护,--daemon 已淘汰
Laravel 11 起 --daemon 模式已被标记为废弃,它无法处理 PHP 扩展崩溃、内存泄漏或超时卡死,一挂就是几十个任务积压。高并发必须用进程管理器兜底。
- Supervisor 配置关键项:
autostart=true、autorestart=true、startsecs=3、stopwaitsecs=30 - worker 启动命令建议带约束:
php artisan queue:work --timeout=60 --tries=3 --max-jobs=100 --sleep=3,防止单任务吃光内存或无限重试拖垮整机 - 别用
queue:listen:它每次取任务都 reload 全量框架,比queue:work慢 3–5 倍,仅限调试
RabbitMQ 在 Laravel 11 下要手动注册服务提供器
如果你选 RabbitMQ 应对极端高并发(比如每秒上千订单),Laravel 11 不再自动发现 laravel-queue-rabbitmq 包的服务提供器,漏掉这步直接报 Driver [rabbitmq] not supported。
- 必须打开
config/app.php,在providers数组末尾添加:VladimirYuldashev\LaravelQueueRabbitMQ\LaravelQueueRabbitMQServiceProvider::class -
RABBITMQ_DSN在 v12+ 版本中已不优先于RABBITMQ_HOST/RABBITMQ_PORT,若两者共存,会忽略 DSN 并拼接 host+port+vhost —— 生产环境建议统一用独立字段配置,避免歧义 -
php artisan queue:declare默认不再创建 exchange,首次发消息时才按需声明;如需预热,得显式调用php artisan queue:declare --exchange=my-exchange
高并发队列真正的难点不在配置语法,而在连接生命周期、数据序列化边界、进程稳定性这三处——它们不会报错,但会让任务在某个流量高峰后批量失败,且日志里找不到痕迹。











