You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Queues/Horizon:如何在多Worker服务器间均匀分配任务

Laravel Horizon 队列Worker集群负载均衡与扩展问题

背景

我有一个基于Laravel 9.x的应用,通过Horizon运行多个资源消耗极大的任务类,目前部署了3台专用Worker服务器运行Horizon,所有服务器连接同一中央Redis实例拉取任务,正在探索队列Worker集群的水平扩展方案。

存在的问题

假设有一个ProcessDocumentJob任务类,3台Worker服务器均监听同一document-processing队列。当我将该任务分发3次到队列时,经常出现一台服务器承接全部3个任务,另外两台闲置的情况,无法充分利用所有服务器的性能。我希望任务能像Web流量负载均衡轮询那样,在所有Worker服务器间均匀分配。

当前解决方案

我给每台服务器设置专属的WORKER_QUEUE环境变量,对应3个不同队列(worker-queue-1、worker-queue-2、worker-queue-3),同时用HORIZON_ENV环境变量设置为"worker"指定对应环境。

horizon.php配置片段

'environments' => [
    'worker' => [
        'worker-supervisor' => [
            'connection' => 'redis',
            'queue' => [env('WORKER_QUEUE')],
            'balance' => 'simple',
            'maxProcesses' => 10,
            'maxJobs' => 0,
            'memory' => 512,
            'tries' => 3,
            'nice' => 0,
            'timeout' => 600,
        ],
    ],
]

ProcessDocumentJob构造函数

public function __construct(Document $document)
{
    $this->onQueue(Worker::bestPick());

    $this->document = $document;
}

Worker::bestPick()是我自己实现的轮询分发逻辑,它会根据可用Worker数量、各服务器对应队列名称以及上一次使用的队列,确定下一个任务分配到哪个队列。

方案缺陷

这个方案多数情况能实现任务均匀分配,但如果某台Worker服务器宕机,除非在Worker::bestPick()中加入可用性检测逻辑,否则会失效。另外我尝试过Redis原子锁和限制maxJobs字段,都没达到预期效果。

咨询问题

  1. 如何实现类似Web流量负载均衡轮询的方式,在所有Worker服务器间均匀分配任务?
  2. 以峰值性能为目标的Worker服务器水平扩展思路是否正确?有没有更贴合Laravel生态的实现方式?

备注:我已了解队列FIFO特性、balance字段的可选值("simple"、"auto"、"false")无法解决当前问题,且已阅读Laravel官方文档中Horizon和队列相关内容。


解答

问题1:实现Worker服务器间的轮询式任务分配

不用自己维护队列映射和轮询逻辑,可以采用以下两种更可靠的方式:

  • 利用Redis消费者分组:Redis 5+支持消费者分组特性,Laravel的Redis队列驱动也兼容该功能。将所有Worker服务器加入同一个消费者组,Redis会自动将任务分发给空闲的消费者,天然实现负载均衡。配置时让所有Worker监听同一队列,在Horizon的supervisor配置中启用消费者分组:
    'worker-supervisor' => [
        'connection' => 'redis',
        'queue' => ['document-processing'],
        'balance' => 'auto',
        'maxProcesses' => 10,
        'consumer_group' => 'document-processing-group',
        'memory' => 512,
        'tries' => 3,
        'timeout' => 600,
    ]
    
    这种方式下,Redis会跟踪每个消费者的任务处理状态,自动分配任务给空闲Worker;Worker宕机后,未完成的任务会被重新分配给存活节点,无需手动维护轮询逻辑。
  • 健康检测+动态轮选:改进现有轮询逻辑,加入Worker健康检测。让每个Worker服务器定时向Redis写入心跳(比如每秒更新worker:{id}:last-seen键值),Worker::bestPick()在选择队列前,先过滤掉超过10秒未更新心跳的Worker,再从存活节点对应的队列中轮选,自动排除宕机服务器。

问题2:峰值性能导向的水平扩展思路及Laravel生态方案

你的扩展思路是正确的,结合Laravel生态工具可进一步优化:

  • Horizon+容器编排弹性伸缩:Horizon的balance=auto模式可在单服务器内根据队列长度调整进程数,跨服务器的水平伸缩可结合Kubernetes,通过监控Redis队列任务长度指标,配合HPA(Horizontal Pod Autoscaler)自动增减Worker Pod数量,实现基于负载的弹性扩展。
  • 任务分片优化:将大任务拆分为多个小任务,比如把ProcessDocumentJob拆成ExtractTextJob、AnalyzeContentJob等细粒度任务,让更多Worker同时处理,提升整体吞吐量,也更容易实现负载均衡。
  • Laravel Octane优化Worker效率:如果Worker进程启动开销大,可用Laravel Octane运行Horizon,基于Swoole或RoadRunner复用进程,减少进程启动的资源消耗,提升Worker处理效率,间接提升集群峰值性能。

内容的提问来源于stack exchange,提问作者Denis Priebe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 02:41:28