课程资料
课程链接:https://live.juejin.cn/4354/yc_Yarn
学员手册:https://juejin.cn/post/7130131931722678308#heading-10
完整手册:https://bytedance.feishu.cn/docx/doxcnECGEFkCKYqbxaDipK1qrVf
课程PPT:https://bytedance.feishu.cn/file/boxcnVGTsGkFnW8ENvQ4bHTdyCg
一、YARN概述
调度系统设计的基本问题
- 资源异质性与工作负载异质性
异质性通常指组成元素构成的多元性和相互之间较大的差异性。资源异质性是从系统所拥有的资源角度来看的,对于大型数据中心来说,其采购往往是分批次的,不同批次的机器硬件配置和计算存储资源都存在较大差异,很难保证采用完全相同的配置,目前主要通过将资源分配单位细粒度划分以及虚拟化技术来解决;工作负载异质性是从系统提交的任务角度来看的,负载类型多样化(流处理、批处理、内存计算、在线服务等),任务偏好多样化和动态化(任务的约束条件、运行过程中资源使用动态变化),资源需求多样化(CPU,内存,GPU,IO等),例如对外服务要保证高可用和快速响应,对于批处理任务要保证快速调度等。
- 数据局部性
大数据场景下因为数据传输开销要远大于计算逻辑传输开销,因此往往将计算任务推送到数据存储所在地进行,这种设计哲学一般被称为数据局部性问题。在资源管理与调度语境下一般存在3种类型数据局部性:节点局部性,机架局部性和全局局部性。节点局部性完成计算不需要进行数据传输,机架局部性需要在机架之间进行数据传输存在一定开销,其它情况则属于全局局部性需要跨机架进行网络传输进而产生较大的网络传输开销,因此最优的方式是尽可能保证节点局部性。
- 抢占式与非 抢占式调度
在多用户多任务场景下,面对已分配资源,资源管理与调度系统有两种不同类型的调度方式:抢占式调度与非抢占式调度。抢占式调度指的是当系统资源不足或存在资源竞争时高优先级的任务可以抢占低优先级任务的资源;非抢占式调度,每次只允许从空闲资源中分配,空闲资源若不足则须等待其它任务释放资源后才能继续推进,mesos采用非抢占式调度。两种方式各有特点,一般如果强调高优先级任务执行效率的调度策略会采用抢占式调度,强调资源公平分配的调度会采用非抢占式调度。
- 资源分配粒度
大数据场景下的计算任务往往呈现层级结构,例如:作业级(Job)-任务级(Task)-实例级(Instance),从计算任务视角来看,此时资源调度系统就面临资源分配粒度问题,资源分配粒度主要存在三种方式:(1)群体分配策略(Gang Scheduler),即要么全满足要么全不满足,Flink和MPI任务依赖这种方式;(2)增量满足式分配策略,只要分配部分资源就可以启动运行,MR采用这种方式;(3)资源储备策略,资源达到一定量才能启动作业,在未获得足够资源时作业可以先持有目前已经分配的资源并等待其他作业释放资源,调度系统不断获取新资源并进行储备和积累,直到分配到的资源量达到最低标准后开始运行,在作业启动前已经分配的资源处于闲置状态。
- 饿死与死锁问题
饿死是由于调度策略不当而导致计算任务长时间无法获得开始执行所需要的最少资源量,例如支持优先级调度时,如果不断出现高优先级任务,那么低优先级任务可能饿死;死锁是由于资源分配不当而导致整个调度系统无法正常执行,例如在资源储备策略下,如果AB两个作业启动作业需要的最小资源为2/3,那么如果两个任务被分配了1/2的资源时,就导致死锁。调度系统出现死锁必然表现为某些作业处于饿死状态,但计算任务饿死的情景并不一定意味着调度系统处于死锁状态。
- 资源隔离方法
为了减少任务之间的干扰需要进行一定的隔离措施,LXC是一种轻量级的内核虚拟化技术,LXC在资源管理方面依赖于 Linux 内核的 cgroups 子系统,cgroups 子系统是 Linux 内核提供的一个基于进程组的资源管理框架,可以为特定的进程组限定可以使用的资源。其他技术有Intel RDT。
调度系统的演进
两层调度系统
- 产生背景:为了解决集中式调度系统的扩展性问题,系统实现复杂,可扩展性差,不能支持不同类型任务等缺点。
- 实现原理:将资源管理和任务调度解耦。集群资源管理器负责维护集群中的资源信息并将资源分配给具体的任务,任务管理器负责申请资源并将申请到的资源根据用户逻辑进行细分和具体的任务调度。
优点:
- 资源管理器只负责资源分配,任务调度由应用完成,提高了系统的扩展性;
- 任务调度逻辑由具体的任务完成,能够提供对不同类型任务的支持;
- 内部实现模块化,利于维护和扩展;
缺点:
- 任务无法感知全局的资源情况,只能基于request/offer来进行资源获取,无法有效避免异构负载之间的性能干扰问题;
- 任务调度和资源管理解耦不利于实现多任务间的优先级抢占;
- 所有任务的资源请求都需要资源管理器进行处理,此外其还需要与节点管理器之间维持通信,导致资源管理器存在单点问题;
YARN整体架构
Resource Manager
- 整个集群的大脑,负责为应用调度资源,管理应用生命周期;
- 对用户提供接口,包括命令行接口,API, WebUI 接口;
- 可以同时存在多个RM、,同一时间只有一个在工作,RM 之间通过 ZK 选主;
Node Manager
- 为整个集群提供资源, 接受 Container 运行;
- 管理Contianer的运行时生命周期, 包括Localization, 资源隔离, 日志聚合等;
YARN上运行的作业在运行时会访问外部的数据服务,常见的如 HDFS, Kafka 等;在运行结束后由 YARN 负责将日志上传到 HDFS
任务运行核心流程
- Client 获取 ApplicationID,调用 ApplicationClientProtocol #getNewApplication。
- RM 返回 GetNewApplicationResponse,其中主要包括:ApplicationID、最大可申请资源以及相关配置。
- Client 将任务运行所需的资源上传至HDFS的指定目录下,并初始化AM配置,主要构造 ApplicationSubmissionContext (应用ID、应用名称、所属队列、应用优先级、应用类型、应用尝试次数、运行AM所需要的资源等)和 ContainerLaunchContext(容器运行所需的本地资源、容器持有的安全令牌、应用自有的数据、使用的环境变量、启动容器的命令行等)。
- Client 将 AM 提交至 RM,调用 ApplicationClientProtocol #submitApplication。
- RM 根据一定的分配策略为 AM 分配container,并与 NM 通信。
- NM 启动 AM。
- AM 从 HDFS 下载本任务运行所需要的资源并进行初始化工作。
- AM 向 RM 注册和申请资源。ApplicationMasterProtocol # registerApplicationMaster,注册信息包括:AM所在节点的主机名、AM的对外RPC服务端口和跟踪应用状态的Web接口;ApplicationMasterProtocol # allocate,相关信息封装在 AllocateRequest中包括:响应ID、申请的资源列表、AM主动释放的容器列表、资源黑名单、应用运行进度。
- RM 接受 AM 请求后,按照调度算法分配全部或部分申请的资源给 AM,返回一个 AllocateResponse 对象,其中包括:响应ID、分配的container列表、已完成的container状态列表、状态被更新过的节点列表、资源抢占信息(强制收回部分和可自主调配部分)等。
- AM 获取到资源后与对应的 NM 通信以启动 container, ContainerManagementProtocol # startContainers
- NM 启动container。
- Container 从 HDFS 下载任务运行必要的资源。
- Container 在运行过程中与AM通信及时汇报运行情况。
- 任务运行完成后 AM 向 RM 注销,ApplicationMasterProtocol # finishApplicationMaster()。
二、核心模块
Resource Manager
整体架构
总的来说,RM 负责集群所有资源的统一管理和分配,接收各节点汇报信息并按照一定策略分配给各个任务;
- 与客户端交互,处理来自客户端的请求
- 启动和管理 AM,运行失败时自动重试
- 管理所有 NM,接收 NM 的汇报信息并下达管理指令
资源管理与调度
- 将资源按照一定方式组织起来,例如:资源池
- 将任务按照一定方式组织起来,例如:队列
- 接收来自各个 AM 的资源请求
- 按照一定分配策略将资源分配给 AM
调度分析
调度流程: YARN 调度流程由心跳触发:
- AM 定期与 RM 保持心跳,并将资源请求记录在 RM 中;
- 触发时机: 由节点心跳触发针对此节点的调度;
- 找 Label: 根据节点 Label 找到对应 Lable 下的所有队列;
- 找队列: 将队列进行 DRF 排序, 找到当前最“饥饿”的队列;
- 找应用: 将此队列内所有应用按照优先级进行排序(优先级由用户提交时指定), 找到优先级最高的应用, 优先级相同时按DRF 算法排序;
- 找资源请求: 将此应用内的所有资源请求按照优先级排序(优先级由计算引擎指定), 找到优先级最高的资源请求进行资源分配;
Node Manager
总的来说,NM 是节点代理,从 AM 接受命令(启停 Container)并执行,通过心跳方式向 RM 汇报节点状态并领取命令(清理 Container)。
与 RM 交互
- 心跳汇报节点健康状况和 Container 运行状态;
- 领取 RM 下达的命令;
与 AM 交互
- 启动容器
- 停止容器
- 获取容器状态