如何在Resque中定义Worker优先级实现高性能节点优先获取任务
Resque本身没有提供节点维度的Worker优先级配置,依托它原生的队列优先级拉取逻辑,配合简单的任务路由就能实现你要的效果,全程不需要修改Resque核心源码,兼容所有正式版本,具体落地步骤如下:
1. 节点分层与Worker启动配置
先给Docker Swarm节点按硬件规格打标签做资源分层:
- 高性能节点(高规格CPU/RAM/GPU):打标签
node.type=high-perf - 普通性能节点:打标签
node.type=standard
两类节点上部署的Resque Worker配置完全不同的队列监听顺序,这是实现优先级的核心:
- 高性能节点的Worker启动时,把核心处理队列放在监听列表最前面,启动命令参考:
QUEUES=video_processing,video_processing_fallback rake resque:work - 普通性能节点的Worker启动时,不要监听核心处理队列,只监听兜底队列,启动命令参考:
QUEUES=video_processing_fallback rake resque:work
所有新提交的视频处理任务,默认全部推入video_processing队列即可。
按照Resque原生的拉取逻辑,高性能节点的Worker只要处于空闲状态,会第一时间拉取video_processing队列的新任务,普通节点的Worker因为没有监听这个队列,完全不会抢占核心任务,优先保证高性能节点资源吃满。
2. 配置任务溢出兜底逻辑
当所有高性能节点的Worker都处于忙碌状态时,核心队列会出现任务堆积,这时候再把溢出的任务导流给普通节点处理,只需要部署一个极轻量的常驻调度脚本(可以跑在Swarm管理节点,资源占用可以忽略),逻辑如下:
- 每1-2秒检查一次
video_processing队列长度,以及当前监听该队列的空闲Worker数量 - 当核心队列无空闲Worker、且任务堆积超过你设定的阈值(比如待处理任务>3个,或最早任务等待时长>10s),就用Redis原子命令
RPOPLPUSH把核心队列里最早入队的任务,按当前普通节点的空闲Worker数量,批量移动到video_processing_fallback队列:redis-cli RPOPLPUSH resque:queue:video_processing resque:queue:video_processing_fallback
这个操作是原子的,不会出现任务丢失、重复消费的问题,单条命令执行耗时在微秒级,不会给Redis造成额外压力。一旦高性能节点出现空闲Worker,会立刻回去拉取核心队列的新任务,不会出现资源闲置。
3. Docker Swarm部署适配注意事项
- 两类Worker服务配置对应的节点部署约束:高性能Worker服务加部署规则
node.labels.node.type == high-perf,普通Worker服务加规则node.labels.node.type == standard,避免Swarm把Worker调度错节点 - 不要用
QUEUES=*的通配符模式监听所有队列,会完全打乱队列优先级顺序 - 如果有特殊资源需求的任务(比如必须用GPU的4K转码任务),可以单独拆分
video_processing_gpu队列,只给配备GPU的高性能节点Worker配置监听该队列,进一步提升资源匹配精度
可选优化
如果想进一步降低任务调度延迟,可以给所有Worker加一个简易心跳逻辑:Worker每完成一个任务、或处于空闲等待状态时,向Redis写入一个带10秒过期的键,记录自身ID、所在节点类型、当前状态。调度脚本不需要轮询Resque的状态接口,直接读这些心跳键就能拿到实时的空闲Worker分布,判断逻辑更精准,延迟可以降到毫秒级。
不要尝试通过修改Resque核心源码实现Worker优先级,后续版本升级会有严重的兼容隐患,上述方案完全基于Resque原生设计,稳定性和原生部署一致。
内容的提问来源于stack exchange,提问作者Caio Nakai

