小红书多媒体任务调度系统的演进优化
导读:视频媒体处理的异步调度是多媒体云基础设施的核心能力之一。本文系统梳理了从 Netflix Conductor 改造而来的第一代调度系统 RedProcess,到面向下一阶段业务规模自研的新一代调度引擎 DES 的演进历程,重点介绍在性能、可用性、功能完备性和运维能力四个维度上的关键架构决策与工程实践。
视频媒体处理在服务端本质上是围绕视频编解码工具的大规模异步任务编排。图片处理可以使用同步实时响应,但视频转码受分辨率、时长、编码算法等因素影响,不同档位间的计算耗时差异悬殊,部分档位之间平均耗时相差 3 倍以上,远超同步接口的合理响应窗口。
因此,视频处理整体采用异步范式:业务方通过 MQ 或 RPC 发起处理请求,任务完成后写入媒资并通过回调通知下游消费。
在此基础上,实际业务流程远不止单一转码操作,而是包含视频 Probe、分支判定、多档位并发转码、媒资写入、业务回调等一系列串并行环节,流程复杂且高度动态。这要求调度系统具备:
DAG 编排能力:支持可视化定义与低成本上线复杂处理流程
跨服务调度能力:任务执行器以微服务组粒度独立部署,调度须跨服务边界
弹性扩缩容能力:应对日内周期性流量波峰与离线任务的大规模积压
2.1 基于 Netflix Conductor 的改造
RedProcess 以 Netflix Conductor 为基础架构原型,但针对内部业务场景做了关键性改造。
Conductor 原生使用 Dynomite(基于 Redis 的分布式 KV 存储)实现任务队列,Worker 侧通过长轮询拉取任务(poll 模式)。在 Worker 节点规模持续膨胀的情况下,如果直接替换为消息队列,会受到 partition 数量上限制约,无法充分水平扩展;而原生 Redis 方案又不具备 MySQL 持久化能力。
RedProcess 的核心改造方向是以 Redis ZSet 为基础自研队列模型:
以 Unix 时间戳作为 ZSet score,通过 Lua 脚本实现原子性的可弹出判定,支持延迟队列语义
通过物理多队列逻辑绑定的方式实现队列优先级分层
数据持久化采用分片可扩展 MySQL 集群,应对海量任务记录的存储诉求
任务防丢机制通过心跳超时 ZSet 实现:Worker 在任务执行期间周期性上报心跳,服务端以心跳超时时间戳(通常为心跳间隔的 3~6 倍)更新 ZSet score;心跳中断后,扫描任务将超时任务重新投递至待分发队列,保障分布式场景下的流程完整性。
弹性伸缩方面,RedProcess 暴露任务队列积压的探针接口,与 Kubernetes HPA 自定义指标集成,实现基于积压深度的自动扩缩容,并支持分时段副本数上下限配置。
2.2 业务规模与集群现状
RedProcess 经过两年迭代,在原有架构基础上支持了垂直多集群、云类型划分、水平单元化部署等重大改造,成为视频云的核心调度基建。主要集群按 SLA 分层:
点播 S0 集群:承载视频发布核心档位与审核抽帧,任务规模较小、流转快,稳定性要求最高,DAG 环节读放大显著
点播 S1 集群:承载高热档位,任务规模大,存在周期性积压,对队列灵活性要求高
点播 S2 集群:承载离线回刷,主要集中在夜间,周期性大规模积压,上游负载完全可控
直播 S0/S1 集群:承载在线直播转码与审核,任务生命周期超长、无积压,心跳频次高、保活需求强,需多云部署
2.3 RedProcess 的架构瓶颈
随着业务规模持续增长,RedProcess 在设计层面的若干缺陷逐渐成为瓶颈:
性能层面:所有任务操作均落地 MySQL,随流量等比放大,扩容成本高周期长。同时自定义字段膨胀(单条记录可达 10~50KB),对 binlog、带宽与内存均产生持续压力。
可用性层面:热门任务类型的队列 key 与执行 key 形成热点,Redis 负载分布严重不均,单节点瓶颈无法通过横向扩容解决。限流降级能力缺失,大流量场景只能依赖上游网关 MQ 限速,缺乏细粒度的垂直业务线限流手段。
功能层面:每类任务使用多个 ZSet 拆分队列,出队时轮询所有队列,效率低且灵活性不足。工作流失败下缺乏回调机制。直播场景对资源的精细管控诉求(平滑扩缩容、发布隔离)无法满足。
运维层面:调度系统无法感知 Worker 版本,问题节点(野 Pod)依然可以获取任务,灰度发布和版本熔断能力缺失。资源分配依赖人工观测与手动调整,缺乏规则化的自动化治理能力。
3.1 整体架构设计
DES(Distributed Execution Scheduler)在保留 DAG 编排灵活性的前提下,针对上述问题从架构层面做了系统性重设计,整体分为 Gateway、Dispatcher、Worker SDK 和 Console 四个核心服务。
Gateway 服务
Gateway 是全局流量入口,统一收口所有持久层读写操作。
Data Handler 层采用 write-back 缓存模式:写入时全量数据直接落 Redis,索引信息写入回写队列,由异步 batch job 统一写入持久层(元数据入 MySQL,非结构化大字段入对象存储);读取时优先命中 Redis,未命中时通过 singleFlight 合并请求后读持久层,有效避免缓存穿透时的惊群效应。Workflow 层数据采用同步回写策略,确保强一致。
持久层故障时,系统自动暂停 TTL 操作并将待处理 key 写入临时集合待后续回捞;缓存层故障时,自动降级至持久层直读直写,配合入口限流保护后端。
Event Handler 负责 ID 生成规范与 DAG decide 驱动,保留与 workflowID 的关联索引性。
DAG Engine 支持 SIMPLE、FORK_JOIN、SWITCH、INLINE、START_WF、SUB_WF、DYNAMIC_FORK、CALLBACK 共 8 种原语,直播链路绕过 DAG 直接生效以降低延迟。
Dispatcher 服务
Dispatcher 是调度核心,承接 Gateway 的 event 分发,完成出队限流、任务下发与节点管理。
Queue Handler 实现全局入队限流、队列重入与插队能力;Poll Handler 收口出队分发逻辑,内部维护 task poll heap,支持基于节点资源余量的稀疏/密集调度策略,并消费节点黑名单屏蔽故障节点的任务拉取。
Worker 通信协议从传统短轮询升级为基于 h2c 的长连接 + SSE 主动推送模式:Worker 建立长连接后,poll 请求注入 heap 等待,Dispatcher 在有任务就绪时通过 SSE 主动下发,显著降低空轮询开销,并对直播等长生命周期任务提供更强的资源管控能力。
Worker SDK
Worker SDK 封装了服务发现、长连接管理、全局事件聚合、任务状态上报等能力。global event handler 负责聚合多个 event handler 的请求并批量发送,同时采集节点 quota 状态并上报 Dispatcher,为服务端的调度决策提供实时数据支撑。重试场景下,DAG 决策不依赖历史失败任务实例的完整数据,只需重试计数,彻底规避了大查询导致的数据库高负载问题。
Console 服务
工作流定义管理收口至 Git 仓库,变更通过 CI/CD 流水线 push 到服务端,实现 Schema 的版本化迭代与审计。任务控制台保留手动任务提交与查询能力,ES 索引精简为 workflow 与 task 两个维度,移除任务日志索引,并从共享集群拆分为独立部署,避免与其他业务相互干扰。
3.2 核心优化详解
性能优化:持久层读写收口与结构重设计
通过 Gateway 统一收口所有持久层操作,将热路径全量数据卸载至 Redis,write-back 批量聚合写入大幅降低 MySQL QPS。表结构重设计中,非结构化大字段从 MySQL 迁移至对象存储,MySQL 仅保留 OSS key 引用;回写队列以 List + 乐观锁实现,保证写入顺序一致性的同时将回写频次收敛在可控范围内。
可用性优化:热 key 拆分与分布式限流
队列 key 以 workflowID 尾号分片,通过 hashkey 机制自动打散至 Redis 集群多节点,消除热 key 集中压力。出队路径引入分布式限流器,支持从 Console 动态下发限流配置,实现业务线与任务类型两级粒度的精细化限流与熔断。
功能增强:智能队列与推送调度
队列优先级从 5 级扩展至 9 级,以 bitmap 替代轮询检测队列非空状态,消除无效轮询的读放大。直播任务支持 workflow 维度的 SSE 推送,任务下发从 Worker 主动拉取转变为服务端主动推送,结合节点 quota 信息实现稀疏或密集调度策略。工作流定义新增 CALLBACK 回调原语,支持非 COMPLETED 状态退出时的错误响应回调。
维护增强:Worker 版本管控与集群合并
Console 支持按任务失败频次或版本标记配置熔断规则,在入队与出队两个环节双重拦截,从根本上解决野 Pod 抢占任务的问题,并具备版本灰度能力。S1 与 S2 集群合并为单一集群,两者在时间维度上流量特征完全互补(S1 白天高峰,S2 夜间高峰),合并后资源利用率显著提升,整体成本下降。
3.3 容灾设计
DES 针对生产环境中曾实际发生的各类故障场景,设计了对应的容灾机制:
集群容量不足:通过在 Worker 中聚合多类任务能力,构建更大粒度的资源池;服务端策略引擎根据实时队列状态决策任务分配,保障高优先级任务受影响最小。
节点不可用(磁盘不可写/GPU 驱动异常):Dispatcher 侧支持服务端主动熔断机制,通过节点失败率实时检测快速识别故障节点,自动拉入黑名单屏蔽任务下发,控制故障传播范围。
高频重试雪崩:针对直播任务超长重试链路及点播业务下游依赖故障导致的批量高频失败,设计重试专用限流通道——超过阈值后,失败任务进入独立队列,避免重试流量冲击正常调度链路。
Redis 集群故障:感知到 Redis 故障后,Data Handler 自动切换至持久层直读直写模式,同时对上游流量做限流,保护 MySQL 和对象存储。
MySQL 维护/禁写:进入 MySQL 维护模式后,系统自动暂停 write-back 队列消费,关闭 workflow 数据强回写,变更数据写入备份队列;MySQL 恢复后自动消费补偿,实现对上游透明的持久层维护窗口。
双云单元架构:Gateway 双云以相同服务名注册,全局流量均分;Dispatcher 默认优先同云访问,跨云任务队列在检测到对端 Worker 存在 idle 状态时拉取,确保算力利用不受双云分布影响。同云任一模块故障时,链路自动通过服务发现切换至对端单元;双云网络中断时,每个单元内部链路完备,具备独立运行能力。全量切换初期在生产环境保留老系统 S0/S1 集群,在新系统发生灾难性故障时可通过上游流量快速回切。
从 RedProcess 到 DES,视频云任务调度系统完成了从"能用"到"好用"的系统性跃升。核心演进路径可归纳为三点:其一,存储分层与读写收口,以 Redis write-back + 对象存储的分层架构承载持久层负载,从根本上解决 MySQL 随流量线性放大的瓶颈;其二,从 poll 到 push 的调度范式升级,基于 h2c 长连接与 SSE 的主动推送模型,在降低调度延迟的同时赋予服务端更强的节点管控能力;其三,容灾体系的系统化设计,从历史故障案例出发,为每类典型故障模式预置对应的自动化降级路径,将人工干预的必要性降至最低。
作者:
夏川(郑跃文) 多媒体基础架构工程师
负责小红书多媒体点直播任务调度系统与点播CPU/GPU资源调度的建设维护与持续优化