京东百万级调度系统(Buffalo)架构解密

作者:京东零售 姬广滕

一、调度系统简介

Buffalo调度是一款京东自主研发的分布式DAG作业调度系统。为京东的数据开发工程师、算法工程师、数据分析师等用户提供了离线作业的编排&调试、监控运维、DAG调度等系统能力,致力于打造行业领先的稳定高效、产品简洁高体验、任务监控全面、资源容器化、系统能力开放化的ETL调度系统。

在京东调度系统核心面临的挑战有以下几个:

1.业务复杂带来的依赖关系复杂: 复杂的数据链路,使得部分任务有数百、甚至上千个上下游,层级多达数十层。跨天依赖、数据回刷、月度汇总等业务场景,需任务间依赖存在大小周期依赖、跨天依赖等复杂场景,任务依赖关系数据构成一个庞大且复杂的有向无环图。

2.业务体量大且稳定性&性能要求高: 目前平台有数十万任务,百万+依赖关系,日均百万+调度频次,不仅关系复杂、执行量大,且系统的任何细微异常,都可能导致数据链路异常,核心数据受损,这对调度系统的稳定性和性能带来了不小挑战。

3.数据加工场景复杂需支撑丰富调度能力: 支持集团多个BG业务,业务场景多样,涉及数据采集、数据计算、数据推送、数据转换等多种任务类型、多种执行方式、多种触发规则,以及控制节点、任务间的数据传递、数据补录场景等,对系统功能的丰富度和灵活度提出新要求。

二、核心技术方案

为支撑灵活的业务加工和工作流编排场景,快速的业务发展带来的任务量增长,以及保障整个系统的稳定性,我们从易用性、稳定性、以及高性能等方面做了很多的思考和优化,下面我将着重从这三个方面详细介绍。

1. 实体和编排调度模型

a) 双层实体模型

采用主流的双层实体模型,双层实体模型中,包含两个核心概念:

Action(环节): 环节是最小粒度的执行单位,携带执行相关的信息,如脚本、参数、环境等。

Task(任务): 任务是由一个或多个环节+触发规则构成的DAG,Task和Task之间也可以相互依赖,在外层构成一个DAG,实现双层调度。

相比单层实体模型,编排能力更强,有更好的灵活性,同时对于单个业务的整合打包和管理也更友好。

b) 基于实例的调度

任务定义是任务配置的载体,无状态,不可执行,任务当到达运行周期时,会产生相应周期的任务实例(产生实例的过程叫"实例化"),实例化时会根据任务的配置信息,包括:环节、上游依赖、数据依赖、运行周期等,生成当前周期实例,可理解为任务的一个快照,任务实例是真正可执行、并具有状态的对象。

基于实例的调度模式,其优点在于:

周期稳定: 任务的每个周期都会有实例,不会出现周期缺失的情况,且每个周期的实例可独立操作

依赖明确: 任务某个周期的实例,其对上游任务实例的依赖,或者数据依赖是明确的、可预期的,同时对某个周期的数据可从整个链路上快速追溯,并在产生问题是可从链路层面快速修复。

c) 分类分级调度能力

平台中的任务不通业务,重要性存在一定差异,为提升核心任务的保障能力,平台提供任务分类分级管理,和基于分级的调度能力,在客户端资源较为紧张时,会优先保障重要业务。同时任务等级信息会透传到底层集群,在底层计算集群层面也增加相应基于分类和等级的保障策略,保障核心业务的稳定性。

2. 高可用架构

buffalo整体有分三层,每一层都具备高可用架构,使得整体具备高可用和容灾能力

a) Manager管理层:

◦主要提供产品化管理能力,包括任务的创建、任务管理、任务运维等,管理端无状态,可横向扩展,负载对外提供服务

b) 高可用Scheduler:

◦也叫NameNode是Buffalo核心调度引擎,负责任务实例的周期生成,以及基于DAG的双层任务实例的调度、客户端资源的调度(物理资源、弹性资源)、任务状态的处理等。

◦整体采用多活+主备高可用架构,多个scheduler会通过数据分片负载处理任务,同时对于任务状态消息进行幂等处理,其中资源调度模块采用主备模式,以便支撑灵活和高效的资源调度能力。当一个节点故障时,其他节点会监测到节点下线,并自动触发接管逻辑,将异常节点任务接管处理,保障故障节点上的任务执行不受影响。

c) 容错执行层:

◦执行层的核心职责是负责任务启动执行,并监听任务执行结果、采集任务日志、上报任务状态,执行层支持物理机和基于k8s的容器化资源两种模式。

物理机: 部署worker(也称TaskNode)长进程,任务以独立进程方式运行,多个worker构成节点组对(虚拟节点)外服务,避免单点故障问题。同时worker本身支持消息重传、cgroup资源隔离等高可用特性。

k8s弹性资源: 与原生k8s对接,任务以短周期pod方式执行,任务结束时pod销毁,天然具备高可用特性,同时具备更精细化的资源管理、差异化执行环境的动态构建能力。

3. 高性能

前面提到调度系统中随着任务量的增长,业务复杂度的提升,需要调度执行的DAG实例梳理,以及DAG的复杂度都会不断提升,buffalo主要从以下几个方面来做到高容量、低延迟的编排和调度。

1) 水平扩展

如上高可用架构部分介绍,调度引擎采用多活架构,可水平扩展,不同服务之间通过数据哈希分片,将任务负载分布到多台服务进行调度,同时各服务通过执行批次和状态进行幂等处理,保障任务执行的唯一性。

2) 事件驱动

a. 定时轮询( 如左图

传统的任务执行方式大多采用定时轮询的方式,这种方式需要定时查询所有待执行的任务实例,然后逐一校验任务实例的依赖条件是否满足(如任务依赖、数据依赖、并发限制等),这种方式在面临大数据量任务时,有几个核心问题:

遍历耗时: 系统中可能有非常多的任务待执行(有些满足条件、有些不满足条件),这样每次获取的任务列表会非常长(可能数十万或百万),这样遍历一遍非常耗时

大量无用计算: 在这些获取的任务列表中,每个任务都需要进行多种条件校验,且只有少数任务是满足执行条件,绝大部分的校验是无用校验

b. 基于事件驱动( 如右图

相比定时轮询,事件驱动不会采用定时拉取、全量校验的方式,而是在任务所依赖条件的状态发生变更时,才会基于事件做出相应的条件计算和校验动作,这样可以有效避免定时轮询面临的两个核心问题。同时针对不同的事件类型,可以分别进行异步并行处理,有效提升整体的处理性能。

3) 内存调度

前面提到Buffalo具备在物理机集群和k8s集群上启动任务执行的能力,所以需要具备这两种资源的管理和资源调度能力,资源调度的性能也是影响任务分发时效的关键部分。

调度引擎namenode采用的是多活的高可用架构,如果资源调度部分也采用该架构(如左图),那么涉及到同一资源的并发访问和修改的问题,进而引入分布式锁和外部存储,这样整体的性能很难达到理想的目标。

因此,我们在namenode多活架构的基础上,将资源调度部分做了一个主备架构的处理(如右图),会从多个namenode里选择一个作为主资源调度器,其他作为热备,所有namenode的任务资源请求都由主节点进行处理,这样主节点在内存中保存了所有的资源信息,资源调度过程在内存中就可进行,避免了分布式锁和对外部存储的依赖,性能有大幅提升。

4) 冷热数据分离

当系统中任务量较大,任务执行产生的实例数据会快速增长,当前buffalo每日的实例数据增量接近百万,随着任务量的增长还会持续增长,如果没有适当的方案来处理,数据库很难支撑如此快速的数据增长。

调度系统中的任务有个明显特征 - 定时 ,就是任务会定时执行,执行完成后的实例,除人为干预外其状态不会再自动发生变更,这部分数据一般只会做查询,所以这部分数据可以做独立存储。我们将状态还会发生变更或频繁操作的数据称作热数据 ,将这些已经执行结束且基本只有查询需求的数据称作冷数据,并将冷数据单独存储。

当冷热数据分离后,有三个核心问题需要解决:

1)数据结转

任务实例执行完成,处于结束状态的实例都可以被结转,目前采用定时结转的策略。为避免冷数据单表数据量过大,结转规则可以按照季度、月或则更小周期进行拆分存储。

2) 数据定位

当数据结转到冷数据表后,这些实例的状态不会发生变更,单可能还会被未执行的实例所依赖,用户也可能会对这些实例做检索操作,所以这些实例需要能从冷数据表中快速被定位。

索引表: 数据结转到冷数据表时,会根据冷数据表的分区粒度,在索引表记录各冷分区表中的数据范围,如计划运行时间在2023-01-01 至 2023-03-31的数据存储在2023Q1分区表,这样在定位时可以圈定数据范围,避免全量扫描

数据定位: 因实例数据是有周期性的,有非常强的时间特性,所以可以结合任务实例的计划运行时间,和索引表的数据范围,快速定位任务某个范围的实例所在的分区。

3)冷数据操作

冷数据被操作的几率比较低,但也存在操作的可能性,比如历史实例的重跑、强制成功等操作。为了保持调度引擎架构的简单性,所有相关的任务执行的处理,都是基于当前表(热表),所以为了能保障被结转的冷数据和热数据一样支持所有操作,冷数据被操作时会从冷数据表恢复至热数据表,从而实现与热数据相同的效果。

4、开放能力

开放API:通过Http协议进行开放,支持任务配置管理、任务实例操作、状态查询、日志查询等能力,通过藏经阁进行开放来服务业务

开放事件:基于JDQ异步消息的方式将任务状态、实例状态进行开放,联动业务个性化处理。状态发生变更及时同步,确保业务触达的及时性

三、未来规划

Buffalo调度系统仍在持续的优化和迭代升级,不仅提供更好的用户体验、更极致的性能,也包括容器化能力、插件化扩展能力、开放能力、精细化的资源管理能力等,希望大家提出更好的想法和建议,一起打造稳定、高效、易用的调度平台。

相关推荐
shining1 天前
当拿到一个新服务器时所需准备工作
linux·程序员
CodeSheep2 天前
同事偷偷给我介绍私活,说1万报酬全给我,结果甲方私下告诉我说,同事在当中白拿了2万,我觉得被耍了,媳妇却让我要知足,说我一点不亏
前端·后端·程序员
程序员鱼皮2 天前
又一个新项目开源,让 AI 帮你盯全网热点!
javascript·ai·程序员·编程·ai编程
loonggg2 天前
一个被99%程序员忽略的效率杀手:你每天盯着看的那块屏幕
程序员
程序员cxuan3 天前
为什么 Claude 要求实名认证?
人工智能·后端·程序员
得物技术3 天前
生成式召回在得物的落地技术分享与思考
算法·性能优化·程序员
JarvanMo3 天前
别拦我!我要在手机上继续写代码
程序员
SimonKing3 天前
AI大模型中转平台,无需科学上网就可以使用国外模型
java·后端·程序员
程序员cxuan3 天前
10 个贼爽的 workflow 工作流
后端·程序员·代码规范
舒一笑3 天前
一文讲透 Temporal:为什么大厂都在用它做 AI 与分布式系统的“流程大脑”?
后端·程序员·llm