必须使用redis或database等支持分布式访问的队列驱动,确保所有服务器连接同一实例;job类定义(命名空间、类名、构造函数签名)须严格一致;各worker服务器需统一queue配置且禁用sync/array驱动。

多个 Laravel 应用怎么共享同一个队列
跨服务器并发处理的前提,是所有 worker 进程(无论在哪台机器上)消费的是同一份队列数据。Laravel 本身不关心 worker 部署位置,只依赖队列驱动的共享能力。
必须使用支持分布式访问的驱动:Redis 是首选,Database 驱动次之;绝对不能用 sync 或 array——它们只在当前进程内存中存在,跨服务器完全不可见。
- Redis 配置需确保所有服务器能连通同一 Redis 实例(或集群),且
queue连接配置中的host、port、database一致 - Database 驱动要求所有服务器连接同一个 MySQL/PostgreSQL 实例,且表结构由
php artisan queue:table统一生成 - 检查
config/queue.php中'default' => env('QUEUE_CONNECTION', 'redis')是否统一,避免某台机器 fallback 到sync
Job 类定义必须严格一致
队列任务不是“代码搬运”,而是“类名 + 参数序列化”。worker 反序列化时会尝试用本地 autoload 加载该类——如果类不存在、命名空间错、方法签名不匹配,直接抛 ReflectionException 或 ClassNotFoundException。
- Web 应用只负责调用
SendInvoiceJob::dispatch($id),但SendInvoiceJob的完整 PHP 文件(含handle()实现)必须存在于所有运行 worker 的后端服务器上 - 推荐将 Job 类放在 Git 仓库中统一管理,部署时同步拉取;不要在 Web 侧写空壳类、后端侧再补实现——版本不同步极易出错
- 构造函数参数类型、默认值、可空性必须完全一致;Laravel 8+ 对 typed properties 更敏感,
public int $id;和public $id;在反序列化时可能失败
如何防止同一任务被多台服务器重复执行
Redis 和 Database 驱动本身已通过原子操作(如 LPOP / SELECT ... FOR UPDATE)保证单个任务只被一个 worker 拿走。但跨服务器场景下,仍需注意几个隐性风险点:
- Redis 连接超时或网络分区时,worker 可能误判任务失败并重发,建议开启
--tries=3并配合failed_jobs表人工核对 - Database 驱动下,若多台服务器的系统时间偏差大(>1s),可能导致
available_at时间判断异常,建议所有服务器启用ntpd或chrony同步时间 - 不要在
handle()内部手动重发任务(如self::dispatch(...)->onQueue('high')),这会绕过原队列的幂等控制,容易引发链式重复
Supervisor 配置要区分服务器角色
你不能在 Web 服务器上跑 worker,也不能让所有后端服务器都无差别启动 4 个进程——资源竞争和日志混杂会掩盖真实问题。
- 明确指定哪几台机器专用于消费队列:例如
worker-01、worker-02,其他机器禁用laravel-workersupervisor service - 每台 worker 服务器的
supervisord.conf中,numprocs值应基于该机 CPU 核心数设定(如 4 核设为numprocs=3),而非全局统一填 4 -
stdout_logfile路径必须带主机标识,例如/var/log/worker-01-laravel-worker.log,否则多机日志会互相覆盖











