导读:大数据任务调度系统负责数据领域所有离线任务的编排调度,是数据中台的重要组成部分。随着任务量变大,调度系统面临调度性能变差和稳定性降低等挑战。本次分享主要讲述快手在每日数十万任务的场景下,如何应对这些挑战,着重介绍在高性能和高可用等方面的建设经验。
本次分享包含四个部分:
- 背景介绍:包括任务调度系统的定位、挑战与目标、以及快手大数据任务调度系统的发展历程;
- 快手大数据任务调度系统整体设计:包括调度模型和系统架构;
- 任务调度系统的关键技术:将聚焦在低调度延迟、高可用和开放能力三部分;
- 任务调度系统的应用、成果和未来规划。
01
快手任务调度背景
对于调度系统,大家应该都不陌生。我们在日常工作中,会碰到很多调度的场景,例如通过定时任务每天发送日报或者选择合适的负载机器来执行任务。根据侧重点不同,调度系统可以分为资源调度系统和任务调度系统。
- 资源调度系统:主要关注底层物理资源的分配,往往管理着较大的物理集群,为使用者提供良好的资源抽象。常见的资源调度系统包括 Yarn、k8s、mesos 等。
- 任务调度系统:主要关注任务及时准确地执行,为使用者提供任务定时、工作流调度等能力。常见的任务调度系统包括 Airflow,DolphinScheduler,Azkaban 等。
资源调度系统和任务调度系统并不是对立的,而是协作关系。任务调度系统常常会依赖于资源调度系统来执行任务。本文将聚焦在任务调度系统。
任务调度在各类场景中发挥着重要作用。大数据的原始数据一般是业务库、服务端日志和客户端日志,这些原始数据的价值密度是很低的。如果要提炼出高价值的信息,往往需要:
1. 经过数据接入进入大数据系统;
2. 然后经过精心建模,层层加工,生产出高价值的数据;
3. 最后经过数据分发到合适的存储引擎中,然后通过服务化提供给数据应用,例如数据分析、在线服务、模型训练等。
在这整个过程中,会有很多任务负责数据的接入、加工和分发。这些任务交织依赖,形成了一个大的有向图。数据生产的核心,就是需要对这个图进行统一调度。为此,需要有一个统一的任务调度系统。任务调度系统是大数据生产的核心,它并不是孤立存在的,会依赖于底层的资源如大数据资源和容器资源,并为上层应用如数据开发、ABTest 平台、指标生产、机器学习等提供服务。
在快手,大数据任务调度系统挑战主要包括三部分:
- 任务量大:有数十万个任务,上百万条依赖关系;这给任务调度系统的性能带来了挑战,大任务量会导致性能恶化。
- 任务交织依赖:任务之间相互依赖,组成一个大的有向图。一个任务可能有上万个上游,也可能有数万个下游任务。这给任务调度系统的稳定性带来了挑战,一个任务的调度出错有可能导致大面积故障。
- 场景多样:调度场景多,执行方式多,任务类型多,给系统的功能带来了挑战,要求功能丰富且可扩展。
与这些挑战对应,目标也包括三部分:
- 高性能:支持百万级任务的调度,调度延迟控制在秒级或者毫秒级;
- 高可用:系统要准时调度,不重不错,且具有高稳定性,避免造成链路数据质量或者数据时效故障;
- 功能强:具有丰富的调度执行方式,具有强大的开放能力,打造丰富的生态体系,为上层应用提供便捷的服务。
纵观快手大数据任务调度系统的发展历程,可以分为四个阶段。
1. 在 2016 年,整体规模较小,采用当时主流 Airflow 作为任务调度引擎。随着时间的推移,快手的业务蓬勃发展,任务规模也急速增长,Airflow 性能和稳定性不再能满足要求。
2. 在 2019 年,为了解决 Airflow 的问题,我们自研了任务调度系统 Kwaiflow,旨在支持百万级别的任务规模。
3. 在 2020 年,我们升级 Kwaiflow 到 2.0 版本,支持例行、触发式、补数据、阻断多个场景,融合质量、安全等数据全生态。
4. 在 2021 下半年,我们开始打造新一代调度系统 Kwaiflow 3.0,以支持秒级调度,支持千万级任务规模。
在过去的五六年,快手的任务数每年成倍数增长,从数千个增长到当前的数十万个,接入的平台数从 0 增长到数十个,用户当前已覆盖公司几乎所有的业务方。
在初期,快手使用 Airflow 当作任务调度引擎,但后来又放弃了。我们为什么会做出这样的选择呢?这就需要分析 Airflow 的优点和痛点。Airflow 是以编程方式创建、调度和监控工作流的开源系统。Airflow 具有很多优点,包括:
- 能力丰富,具有丰富的任务类型,易用的流程控制;
- UI 易用,较为方便地进行可视化运维;
- 组件少易部署,上手难度不大。
这些优点是我们选择 Airflow 的原因。
但随着任务规模增大,Airflow 的痛点也很明显:
- 性能较差:我们发现,当 Airflow 单集群 Dag 数近 1 万时,单任务调度延迟 P99 高达 5min,链路调度延迟高达数十分钟,链路时效性难以保障。为了满足业务增长,我们搭建了多个集群,运维成本倍增。
- 稳定性不足:当时 Airflow Scheduler 没有 HA,任务执行时环境和资源不隔离,容易 OOM,导致调度故障比较多,年均故障数约 8 个。
- 集成度低:二次开发成本大,和周边系统集成度低,开放能力差,难以快速构建生态。
由于这些痛点的存在,我们决定自研任务调度系统。
02
快手任务调度整体设计
在 2019 年中旬,我们开始自研任务调度系统 Kwaiflow,并在下半年上线 1.0 版本。
Kwaiflow 是快手通用、高性能、易扩展的分布式工作流调度系统。其设计目标从两方面考虑。
在功能型目标方面:
- 场景丰富:支持多场景调度,多种环境执行,支持多样易扩展的任务类型
- 运维便捷:可以进行可视化、智能、便捷地运维
- 便于开放:具有强大的开放能力,易于系统集成,构建统一生态
在非功能型目标方面:
- 高容量:支持百万级任务容量
- 高性能:秒级或者亚秒级调度延迟
- 高可用:可用性 99.99%,线上问题少,出现时能及时发现快速并处理
在定位上,Kwaiflow 基于大数据体系和其它基础设施,提供调度、执行等核心能力,同时具有运维、监控报警、智能诊断、开放服务等重要能力,构建调度生态;面向数据处理、流程编排、算法调度和分布式计算等场景。
在调度模型上,Kwaiflow 采用了两层实体的调度模型:
- Task:执行模板,用于执行某一类型的代码;Task 有很多类型,例如 HiveTask 用于执行 Hive SQL,BashTask 用于执行 Bash 脚本,HivePartitionSensorTask 用于探测 hive 表分区是否存在。
- DAG:一系列 Task 的集合,具有调度定时等属性。
在依赖关系方面,DAG 之间可以相互依赖,既可以同周期依赖,也可以跨周期依赖,还可以有依赖偏移。DAG 内的 Task 之间也可以依赖,由于他们调度属性一致,所以都为同周期依赖。
一般来讲,常见的调度模型除了双层实体模型外,还有单层实体模型。单层实体模型没有 DAG 的概念,只有 Task,Task 具有调度属性,Task 之间相互依赖。两种模型各有优劣。双层模型更适合快手的情况,具有更强的表达力,使用场景更广泛,当然也具有一定的复杂性。
在系统架构上:
- API Server 提供各式各样的接口,负责统一接入。
- Scheduler 负责调度,不同的调度场景会有不同类型的调度器,包括例行、触发式、补数据、阻断调度器。在例行调度器中,任务实例生成后,会依次经过定时检测、依赖检测和资源检测。如果都通过,会提交到 Queue Service 中。
- Queue Service 为带 ack 机制的消息队列服务,会有不同的 channel,以便隔离任务。
- Worker 负责任务的执行,从属一个 worker 分组。不同分组的 Worker 消费 Queue Service 中不同 Channel 的任务,根据不同的任务类型进行执行。执行分为本地执行和容器化执行两种方式,本地执行是指任务实例在 worker 内通过新建进程的方式执行;具有启动快的特点;容器化执行是指在 k8s 远程执行用户代码,具有资源隔离和环境隔离的特点。
除此之外,还有其它关键模块,包括日志服务、报警服务、事件服务、实例血缘服务等。
03
快手任务调度系统关键技术
1. 关键技术:低调度延迟
调度延迟是指理论起调时刻到实际开始运行用户代码的时间差。调度延迟是衡量任务调度系统性能的重要指标之一,该指标越小越好。
任务实例从生成,到开始运行用户代码,需要经过等待时间就绪、等待依赖就绪、等待资源就绪和准备运行环境四个阶段。要有较小的调度延迟,就需要减少各个阶段的系统时间损耗。调度延迟的主要因素与处理方案有:
- 定时器。定时器在探测时间就绪环节起作用,一个精准的、支持百万级别高吞吐的定时器,对低调度延迟至关重要。优秀的定时器,时间损耗可以控制在毫秒内。
- 数据库访问。任务实例状态发生变更后,需要对状态进行持久化。通过索引、读写分离、分库分表等方式,可以将单次数据库访问耗时控制在 1 ~ 3ms,总体耗时控制在 10ms 左右 。
- 状态转变。任务实例自生成到运行结束,会经历多次状态转变。状态转变高效与否是调度延迟的重要因素。一般来说有两种办法:轮询与事件触发。我们采用的是事件触发方式,第一时间感知状态转变。通过事件触发,时间损耗可以控制在毫秒内。
- 运行环境准备。这个环节主要工作包括加载镜像、初始化运行环境等。我们主要采用了预加载和镜像预热技术。不同的运行环境,时间损耗不一样,会在亚秒到分钟不等。
这四个因素中,后两者相对较复杂,接下来着重介绍状态转变和运行环境准备这两部分。
首先看状态转变这个因素。任务从发布,到调度执行完成,会经历数次或者十数次状态变化。如何进行快速高效地状态转变是一个重要的问题。Kwaiflow 的解决办法是采用 Akka actor。充分利用了 akka actor 高性能特点。
具体来讲:
1. Kwaiflow 的任务从 API Server 发布后,经过 Entry Actor 加载到 DagLoader Actors 中等待时间就绪;
2. 在时间就绪后,由 Instance Generator Actors 生成任务实例,然后进入 Dependency Detector Actor 探测上游依赖就绪情况;
3. 在依赖就绪后,进入 Resource Detector Actor 探测资源就绪情况;
4. 在资源就绪后,任务实例通过 Queue Service 下发到 worker 中。
5. 任务实例在 worker 被接收后,将会由 Processor Actor 执行,执行前后会依次经历代码渲染、Prehook、代码执行、Posthook 四个步骤。
6. 如果执行成功,则流程终止;如果执行失败,Posthook 会将信息通过 Processor Actor、ResultHandlerActor 传递给 scheduler 的 RetryerActor 进行重试操作。
整个流程具有三个特点:
- 全流程事件触发:无轮询,任务发布、调度、执行、重试,均为事件触发。
- 高吞吐:采用异步并发的方式,能快速调起大量任务实例
- 简单易用:无需使用底层 API 进行锁和线程管理,专注业务实现。
采用 actor,状态转变导致的时间损耗控制在毫秒级别。
接下来我们看运行环境准备这个因素。这和执行场景有关。为了满足不同的执行场景,Kwaiflow 提供了两种执行方式:容器化执行和本地执行。
- 容器化执行:任务实例每次执行前,在 k8s 按需申请容器资源,在容器中执行任务实例,执行完后,及时释放容器资源。优点是实现了执行时的资源隔离和环境隔离;缺点是每次都需要申请和初始化容器资源,启动耗时长。容器化执行适合对资源、环境敏感的任务,例如 Bash 任务。为了减少容器化执行的启动耗时,我们将镜像分为自定义镜像和通用镜像,对通用镜像进行预热,提前分发到机器中,减少镜像下载耗时。通过镜像预热,可以将启动耗时从分钟级降低到秒级。
- 本地执行:任务实例在 worker 机中,通过新建进程的方式执行。同一个 worker 机中的所有任务实例共享计算资源和执行环境。优点是启动耗时短,overhead 小;缺点是资源和环境不隔离,一个任务实例执行异常有可能导致整个 worker 机 crash。本地执行适合对资源、环境不敏感的任务,例如 Hive 和 Sensor 任务。本地执行的启动耗时一般在亚秒级。
2. 关键技术:高可用
高可用对调度系统来说非常重要。为了保障 Kwaiflow 的高可用,我们主要从两方面进行考虑:系统设计和故障发现处理。在系统设计上,Kwaiflow 可以做到高可靠执行,即任务实例在复杂环境中 Exactly Once 执行,做到不漏,且尽量不重。
对于高可靠执行,常见的故障场景包括组件故障或者组件失联。例如 scheduler crash、容器化任务与 worker 失联等。
为了达到高可靠,我们主要从三方面考虑:
- Failover 机制方面:通过自动故障转移和鲁棒通信协议,来实现组件的自动容错。例如 Kwaiflow 采用主备 Master,多 worker 的设计来避免单点问题;各个组件之间采用鲁棒通信协议来避免失联问题。协议包括 scheduler Executor 通信协议、Executor Runner 通信协议、External Job 通信协议。右图展示了 Executor Runner 通信协议的主要流程,协议规定了任务提交、正常执行、异常执行、通信失联的处理办法,不依赖外部系统的状态。
- 避免遗漏执行方面:通过消息 ack 机制,保障消息不丢失;同时通过定期兜底巡检,保障任务实例不遗漏。
- 避免重复执行方面:通过状态机转移图,避免不合理状态转变;同时通过重试前清理前一个实例,避免重复执行。
高可用方面,还有一个重要的系统设计是分级保障。快手在进行大型活动例如春节、奥运时,整体数据量大幅度增长,局部数据呈数倍增长。但计算资源是有限的,计算资源的增长往往不能匹配数据量的增长,不能让所有的任务和往常一样按时产出。这时候我们就需要进行分级保障。
所谓分级保障,就是在资源有限的情况下,让高优任务得到特权,优先得到执行,优先获得充足的优质资源,保障产出时间;而低优任务则会被延迟调度执行,分配更少的资源。
在快手,整个离线体系,包括 Kwaiflow、Hive、Yarn、HDFS 等,都具有分级保障的能力。这里介绍 Kwaiflow 的分级保障能力,包括三方面:
- Kwaiflow 调度器具有分级调度的能力。Kwaiflow 调度器能感知到资源调度系统的状态,在资源不足时,Kwaiflow 任务会在调度器排队,高优任务排在前面,低优任务排在后面;当资源得到释放时,高优任务优先被调度。
- Kwaiflow 的执行器按照不同优先级进行分组。包括三组:P0 执行器组、P1 执行器组以及 P2 P3 执行器组。P0 执行器用于执行最高优先级的 P0 任务,具有充足的 worker,P0 任务实例基本不会在执行器层被限制。对于 P2 P3 分组,在调度高峰期,任务实例很多时,可能存在排队执行的情况。
- Kwaiflow 具有较强的人工管控能力,可以人为地允许或者阻断某些任务的调度。典型使用场景是在大型活动期间,可以根据预案,对低优先级的任务人为进行延迟调度,保障资源分配给高优任务。
前面主要从系统设计方面介绍了线上故障的自动规避。Kwaiflow 高可用的第二个方面是故障的发现和处理。如果故障发现不及时、处理不迅速,会出现大规模的调度错误或者调度延迟故障。在快手调度系统发展的过程中,我们碰到过这样的大故障,为了避免再次发生,我们建立了完备的监控预案体系。
- 在监控方面,我们分成使用层、服务层、依赖层三个层次,并划分监控优先级,采用不同的响应方式。
- 在故障预案方面,我们有两类预案:系统故障处理预案用于处理调度系统自身问题;数据异常处理预案用于处理链路数据不正确的问题。我们沉淀了多场景的阻断恢复和补数据工具,能够在数分钟内启动数据恢复。
- 在演练方面,我们定期对预案进行演练,保证预案的可用性,操作的熟练性。
3. 关键技术:开放能力
开放是数据中台的核心竞争力。只有足够开放,才能给予使用者自由的发挥空间,满足更多使用场景;只有足够开放,才能构建数据生态,提供更丰富的能力。Kwaiflow 提供了多种开放能力:
- Kwaiflow 具有开放的 API,支持多语言 SDK,提供了标准化的接入流程、使用手册和接入 demo。
- Kwaiflow 提供了标准的事件。包括任务操作事件、任务实例状态变更事件、任务实例诊断事件等。根据这些事件,可以完整复现出任务和任务实例的全生命周期。
- Kwaiflow 提供了插件化任务类型。开发者可以定义和开发自定义的任务类型,并进行灵活测试、灰度上线和管理。
- Kwaiflow 提供了 Hook,可以在用户代码运行前后执行。包括执行前的 Prehook 和执行后的 Posthook。常见场景包括用于代码渲染、前置检查的 Prehook,以及用于执行后数据质量检测的 Posthook。
04
快手任务调度系统的应用与成果
如果把任务调度系统比作大楼的骨架,那么基于任务调度系统的应用就是装修完善、适于人工作生活的大厦。通过应用,能更好地体现任务调度系统的价值。在快手,集成开发平台是任务调度系统的一个典型应用。
集成开发平台是快手的一站式离线数据开发平台。它使用 kwaiflow 作为统一的编排与调度系统,构建了各类的数据开发运维等服务,提供了数据查询、同步、开发、服务化、运维、管理等能力。
该平台具有三个特点:
- 一站式:平台涵盖离线数据开发的各环节,包括数据接入、数据加工、数据分发和数据服务化。用户可以方便地进行数据源管理,创建数据接入任务将各种数据源导入到大数据系统中;用户可以通过智能 IDE 编写、测试和发布 ETL 任务,对数据进行加工处理,产生高价值的数据;用户还可以创建数据分发任务,将高价值数据分发到其它存储引擎中,例如关系型数据库、非关系型数据库、缓存系统、OLAP 引擎等。用户也可以直接通过配置的方式创建服务化 API,为线上系统提供服务。
- 通用:集成开发平台能统一运维 Kwaiflow 所有任务,包括任务运维、实例运维、链路运维等方式,适合数据开发、定时调度、触发式调度等场景。
- 智能:在开发环节,通过智能 IDE,能及时发现代码问题;在运维环节,通过智能监控、智能诊断,能及时发现任务和链路问题,并辅助定位问题原因。
任务调度系统要得到广泛使用,不仅要有强大的自身能力,更要有丰富的生态体系。在快手,Kwaiflow 和大数据的其它系统深度集成,接入了 Kwaiflow,便可以便捷地使用其它大数据系统的能力。可以说,自身能力和生态体系对 Kwaiflow 来说同等重要。
首先,就自身而言,Kwaiflow 具有强大的调度执行能力。包括多场景调度能力、多样化的执行能力、易用的运维能力和高可用的特性。
其次,Kwaiflow 具有资源管控能力。接入 Kwaiflow,便可以方便地使用大数据资源和容器资源。
最后,Kwaiflow 无缝集成了其它中台能力。包括数据质量、数据安全体系、完整准确的任务实例血缘、链路元数据、链路保障体系。
将从性能、功能和使用情况三个方面介绍 Kwaiflow 的成果。
在性能方面,和 Airflow 相比,有极大的提升:
- 在规模上,Kwaiflow 初版设计容量为百万级别任务,当前已有数十万的任务数,和 Airflow 单集群不超过 1 万相比,提升了数十倍。
- 在性能上,Kwaiflow 调度高峰期的调度延迟 P99 小于 5 秒,和 Airflow 5 分钟相比,有数量级的提升;Kwaiflow 起调速率十数万每分钟,和 Airflow 数千每分钟对比,提升了数十倍;Kwaiflow 运行的并发实例数十数万万,和 Airflow 小于1万相比,提升了十数倍。
- 在稳定性上,Kwaiflow 可用性为 99.99%, Airflow 则为 99.5%;Kwaiflow 年故障数约 1 个,而 Airflow 年均为 8 个。
在功能方面,Kwaiflow:
- 具有强大的调度能力,支持多调度场景、支持各种复杂依赖流程编排。
- 具有灵活的执行方式,丰富易扩展的任务类型。
- 具有便捷的运维中心,任务、实例、链路可视化运维,智能化运维。
- 具有多种资源管控能力,支持多租户,可方便使用和管理大数据与容器资源。
- 全面集成数据中台能力,包括数据质量与安全体系、血缘、元数据、链路保障体系。
在使用情况方面,Kwaiflow:
- 面向全公司,接入了数据、算法领域数十个平台,包括指标模型管理平台、AB 测试平台、用户画像、机器学习平台等。
- 面向主站、电商、商业化、海外、游戏等几乎公司所有业务方。
在未来,Kwaiflow 主要朝着三个方向发展:
- 更通用化:更好地支持触发式调度,更复杂的在线流程编排,探索分布式计算。
- 更高性能:更好地支持秒级调度,支持千万级规模任务实例,支持大规模触发式调度。
- 更丰富的功能:更丰富的容器资源管理能力,完善的自动化测试系统和大规模模拟演练系统,更加快速的部署能力。
今天的分享就到这里,谢谢大家。
本文经授权发布,不代表增长黑客立场,如若转载,请注明出处:https://www.growthhk.cn/cgo/product/64351.html