解析:分布式应用框架Ray架构源码-3

Leo Xiao 发表于 2021/03/15 17:58:14 2021/03/15
【摘要】 资源管理和调度Ray中的资源是任何“Key”->浮点数。为方便起见,Ray调度程序原生支持CPU、GPU和内存资源类型,Ray会自动检测每个节点上可用资源。同时,用户也可以使用任何有效字符串定义自定义资源需求,例如,指定{“某物”:1}的资源要求。分布式调度程序的目的是将来自所有者的资源请求与集群中的可用资源相匹配。资源请求是硬调度约束。例如,{“CPU”: 1.0, “GPU”: 1.0...

资源管理和调度

  • Ray中的资源是任何“Key”->浮点数。为方便起见,Ray调度程序原生支持CPU、GPU和内存资源类型,Ray会自动检测每个节点上可用资源。同时,用户也可以使用任何有效字符串定义自定义资源需求,例如,指定{“某物”:1}的资源要求。
  • 分布式调度程序的目的是将来自所有者的资源请求与集群中的可用资源相匹配。资源请求是硬调度约束。例如,{“CPU”: 1.0, “GPU”: 1.0}表示对1个CPU和1个GPU的请求。此任务只能在具有>= 1 CPU和>=1 GPU的节点上调度。每个@ray.remote函数都需要一个CPU执行({“CPU”: 1})。默认情况下,Actor,即@ray.remote类,将请求{“CPU”: 0}进行放置。
  • 有一些资源具有特殊处理:
  1. Ray启动时自动检测“CPU”、“GPU”和“内存”的数量。
  2. 将“GPU”资源分配给任务将自动设置工作线程中的CUDA_VISIBLE_DEVICES env var,以将其限制为特定的GPU ID。
  • 需要注意的是,Ray不强制实施资源限制(Acor内存除外:如果指定,则在每个任务结束时检查Actor的内存限制),用户可以指定准确的资源要求,例如,为具有n个线程的任务指定num_cpus=n。Ray所需资源的主要目的是准入控制和智能自动扩展。

任务调度(owner-raylet)

依赖解析

  • 任务调用者在从分布式调度程序请求资源之前等待创建所有任务参数。在大部分情况下,任务的调用者也是任务参数的所有者。例如,对于像foo.remote(bar.remote())'这样的程序,调用者拥有这两个任务,并且在bar完成之前不会安排foo。这可以在本地执行,因为调用者将将bar`的结果存储在其进程内存储中。
  • 任务的调用者可能正在使用任务参数,例如它从owner那里收到了参数ObjectRef的反序列化副本。在这种情况下,任务调用者必须通过执行具有参数所有者的协议来确定参数何时创建。借用程序进程在反序列化ObjectRef时与owner通信,创建对象后owner响应,借用者将对象标记为就绪。如果owner失败,借用者还将对象标记为就绪,因为对象与其所有者共享命运。
  • 任务可以有三种类型的参数:纯值、内联对象和非内联对象。
  1. 纯值:f.remote(2)
  2. 内联对象:f.remote(small_obj_id)
  3. 非内联对象:f.remote(large_or_pending_obj_id)
  • 纯值不需要依赖关系解析。
  • 内联对象是小到可以存储在进程内存储中的对象(默认阈值为100KB),所有者可以直接将这些复制到任务说明中。
  • 非内联对象是存储在分布式对象存储中的对象。这些对象包括大对象和已由所有者以外的进程借用的对象。在这种情况下,Owner将要求raylet在调度决策期间考虑这些依赖关系。raylet将等待这些对象成为其节点的本地对象,然后再为从属任务授予工作租约。这可确保执行工作程序在收到任务时不会阻塞,等待对象成为本地对象。

资源履行

  • Owner通过向其本地raylet发送资源请求来调度任务,raylet将请求排队,如果它选择授予资源,则使用现在租给owner的本地工作器的地址响应owner。只要owner和租赁的工作人员处于活动状态,租赁就会保持活动状态,并且raylet确保在租赁处于活动状态时,任何其他客户端都不能使用该worker。为确保公平性,如果没有工作剩余或已经过了足够的时间(例如,几百毫秒),owner会直接返回给worker。

如上图:“Dounble(2)”任务的资源履行和执行是在Ray cluster中进行的。

  • 只要这些任务与授予的资源请求兼容Owner可以将任何数量的任务安排到租赁的worker上,因此,租赁可以被视为一种优化,以避免与类似调度请求的调度程序通信。

如上图Owner可以持有多个工人租约,以增加并行性。工作器租约在多个任务中缓存优化,减少scheduler上的负载。

  • 如果raylet选择不在本地授予资源,它还可以使用远程raylet的地址响应所有者,所有者应在该地址重试资源请求。这称为溢出计划。溢出调度是迭代的:每个raylet都会使用要尝试的下一个raylet的地址响应所有者,而不是直接转发资源请求。这可确保owner关于任务位置的元数据始终一致。

如上图:在溢出计划期间,raylet将所有者的请求重定向到具有可用资源的远程raylet。
参考代码:

  • src/ray/core_worker/core_worker.cc
  • src/ray/common/task/task_spec.h
  • src/ray/core_worker/transport/direct_task_transport.cc
  • src/ray/core_worker/transport/dependency_resolver.cc
  • src/ray/core_worker/task_manager.cc
  • src/ray/protobuf/common.proto

分布式调度(raylet-raylet)

Resource Accounting

  • 每个raylet跟踪其节点的本地资源。当资源请求被授予时,raylet会相应地降低本地可用资源。一旦资源被返回(或请求者死亡),raylet将相应地增加本地可用资源。因此,raylet始终具有本地资源可用性的高度一致视图。
  • 每个raylet还从GCS接收有关群集中其他节点上资源可用性的信息,用于分布式调度,例如,在集群中的节点之间进行负载平衡。为了减少收集和传播的开销,这些信息使用最终一致性策略:它可能是过时的信息,信息通过定期广播发送,每个心跳间隔(默认为100ms),每个raylet都会将其当前资源可用性发送到GCS服务。GCS聚合这些心跳,并将它们重新广播到每个raylet。

Scheduling Policy

raylet总是尝试首先使用本地资源授予资源请求。当没有当地资源时,还有三种其他可能性:

  1. 根据GCS发布的可能陈旧的信息,另一个节点有足够的资源。raylet将请求溢出到另一个raylet。
  2. 当前没有节点有足够的资源。任务在本地排队,直到本地或远程节点上的资源再次可用。
  3. 群集中没有节点具有请求的资源(例如,仅CPU群集中的{“GPU”: 1}请求), 这项任务被认为是不可行的, raylet会向相应的驱动程序发出警告消息,将任务排队,直到有可用的资源,例如1个GPU的节点添加到集群中。
  • raylet已规划了基于locality的的调度决策(即,将任务溢出到已经具有本地任务参数的节点)。对象locality当前未实现。
  • 参考代码:
  1. src/ray/raylet/node_manager.cc
  2. src/ray/protobuf/node_manager.proto

AutoScaler

  • Ray Autoscaler(也叫Cluster Launcher), 负责启动一组初始群集节点,并根据资源需求根据需要添加其他节点。
  • 在Ray版本<= 1.0.1中,自动缩放器是这样实现的:
  1. 它根据当前分配的资源计算群集的估计利用率。例如,假设群集分配了100/200个CPU,但分配了15/25个GPU,则利用率为max(100/200,15/25)=60%。
  2. 如果估计利用率大于目标(默认为80%),则自动缩放器将尝试将节点添加到群集。
  3. 如果节点空闲超时(默认5分钟),则将其从集群中删除。
  • 在Ray版本1.1+中,调度实现如下:
  1. 它计算满足所有当前挂起的任务、参与者和放置组请求所需的节点数。
  2. 启动新节点。
    a. 如果所需的节点总数除以当前节点数超过1 + upscaling_速度,则启动的节点数将受到该阈值的限制。
    b. 当节点通过request_resources()启动时,将绕过upscaling_速度限制。
  3. 如果节点空闲超时(默认5分钟),则将其从集群中删除。
  • 新算法的优点是,它精确地扩容以满足资源需求所需的节点数量,而以前的算法只使用聚合利用率数据,因此它无法确切知道需要多少节点.
  • Ray还支持多种群集节点类型。群集节点类型的概念包括物理实例类型(例如,AWS p3.8xl GPU节点vs m4.16xl CPU节点),以及其他属性(例如,IAM角色、镜像等)。可以为每个节点类型指定自定义资源,以便Ray了解应用程序级别对特定节点类型的需求(例如,任务可能通过自定义资源请求将其放置在具有特定角色或镜像的机器上).
    参考代码:
  • python/ray/autoscaler/_private/autoscaler.py
  • python/ray/autoscaler/_private/resource_demand_scheduler.py
  • python/ray/autoscaler/node_provider.py

Customer Resources

除了CPU、GPU和内存等本机系统资源之外,Ray还支持自定义资源的定义和使用。这些功能通常在启动时添加到节点中,例如,节点可能会通告它具有具有自定义资源的特定硬件功能和数据集{“HasHardwareFeature”: 1, “HasDatasetA”: 1}。任务和参与者可能需要一定数量的此资源(例如0.01)来调度,这有效地限制了它们在该特定节点上运行。自定义资源也可以通过任务动态添加到节点中。

Placement Groups

Ray从1.0开始支持Placement Group, Placement Group允许用户在多个节点上原子地保留资源组(即Gang调度),他们可以请求组成组的资源捆绑包尽可能靠近(PACK)或分散(SPREAD)。可以销毁组以释放与组关联的所有资源,Ray Auto Scaler感知放置组,并自动缩放群集,以确保可以根据需要放置等待的组。

Multi-tenancy

Ray从1.0开始支持多租户,将支持的多租户的基本级别是为不同作业的工作人员设置不同的环境变量,这允许多个软隔离环境(例如,不同的PYTHONPATH、Java类路径)存在于一个Ray集群中。为确保隔离,启用多租户时,工作进程不会在不同的作业中重复使用。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。