ZenML Pro 资源池调度机制全解:Resource Pool Reconciliation 的运行时流程与抢占策略

发布时间:2026/9/18 14:27:19
ZenML Pro 资源池调度机制全解:Resource Pool Reconciliation 的运行时流程与抢占策略 ZenML Pro 资源池调度机制全解Resource Pool Reconciliation 的运行时流程与抢占策略【免费下载链接】zenmlZenML : One AI Platform from Pipelines to Agents. https://zenml.io.项目地址: https://gitcode.com/GitHub_Trending/ze/zenmlZenML Pro 的资源池Resource Pool功能为动态流水线dynamic pipelines提供了一套共享、可抢占、可配额的容量调度模型。本文以 ZenML 官方文档中关于**资源池调和Resource Pool Reconciliation**的说明为主体深入拆解一条 step 从发起资源请求、排队等待、抢占调度到资源释放的完整运行时流程并结合仓库源码src/zenml/config/resource_settings.py、src/zenml/zen_stores/sql_zen_store.py与配套文档核心概念、示例工作簿讲解reserved、limit、priority、preemptible四个关键参数如何协同工作。读完本文你将掌握资源池调和的调度顺序、抢占触发条件与受害者选择规则并能据此设计出生产有保障、实验可突发的多团队共享 GPU 策略。运行时流程Orchestration一次资源请求的完整生命周期调和器reconciler是 ZenML Pro 中保持资源池状态一致的幕后进程。在自托管 Kubernetes 场景下它作为工作区服务器的一个独立微服务运行详见 启用工作区服务器资源池。对于一条参与资源池调度的 step其请求从产生到释放共经历六个阶段1. 请求创建Request Creation对于符合条件的运行eligible runs服务器会从 step 的ResourceSettings推导出请求的资源量自动追加step_run: 1表示一个并发 step 运行槽位并从同一份设置中记录该 step 是否可抢占preemptible。请求方resource requester是当前 stack 中的 step operator——如果该 step 使用了 step operator否则就是 orchestrator。在源码层面这一逻辑位于 src/zenml/zen_stores/sql_zen_store.py当资源池功能开启、step 处于INITIALIZING/PROVISIONING/RUNNING状态且存在resource_requester时服务器调用requested_resources step_config.config.resource_settings.merged_requested_resources() requested_resources[step_run] 1merged_requested_resources()定义在 src/zenml/config/resource_settings.py它将ResourceSettings的强类型字段转换为资源池使用的键值对强类型字段请求键换算方式gpu_countgpu直接取值gpu_count 0时写入cpu_countmcpumath.ceil(cpu_count * 1000)即毫核memorymemory_mb按字节单位换算为 MB 后向上取整pool_resources自定义键名原样复制被强类型字段覆盖同名键随后以preemptiblestep_config.config.resource_settings.preemptible创建资源请求。注意preemptible的默认值是True见 resource_settings.py 中的preemptible: bool True。2. 排队Queuing如果容量无法立即满足step 可以保持在队列中直到调和器为其分配资源。排队是资源池实现公平调度的核心同一池内多个请求按策略优先级priority与到达时间排序高优先级请求被优先处理。3. 客户端等待Client Waitstep 启动器step launcher会以带退避的重试backoff轮询资源请求直到其被分配。如果请求最终被拒绝rejected、被抢占preempted或被取消cancelled客户端会向用户抛出错误一旦分配成功该 step 被标记为运行running并继续执行。这意味着排队等待对流水线作者是透明的——step 代码不需要处理调度细节只需在运行视图观察queued / allocated / rejected状态即可。4. 抢占Preemption如果队列头部的作业仍然无法被授予资源调和器可能会停止池内其他可抢占preemptible的运行以释放单位容量详细规则见下文抢占如何工作一节。不可抢占non-preemptible的运行永远不会以这种方式被停止。此外不可抢占的运行还受一条硬约束每个请求的每键需求量必须 ≤ 该键的策略 reserved——即使 limit 更高也不行——这样它们永远不会依赖可能与其他不可抢占使用冲突的借用容量。5. 抢占后重试Post-Preemption Retry被抢占后如果 step 配置允许重试step 会重新回到队列并再次尝试执行如果重试次数耗尽或未配置重试step 失败。这与 ZenML 的自动 step 重试Automatic Step Retries机制衔接——建议在配置 step 时明确max_retries策略避免关键作业因一次抢占而直接失败。6. 释放Deallocation当 step 运行完成时资源被释放回池中。如果 step 意外崩溃资源最终也会被释放回池中由调和器兜底回收防止僵尸占用。⚠️多策略、多池的边界规则如果资源请求方orchestrator 或 step operator将多个策略policy绑定到多个池同一个逻辑请求可能会出现在多个池的队列中但调和器最多只授予一个活动的分配。每个池都针对完整的资源请求单独计算资格系统绝不会把 step 的一部分需求分配给池 A、另一部分分配给池 B例如 GPU 来自一个池、mcpu来自另一个池是不允许的。抢占如何工作How Preemption Works抢占是资源池实现弹性共享的关键机制。理解它需要回答三个问题何时触发、谁可以被停止、谁先被停止。何时触发抢占只有当下一个排队中的请求无法被分配时才触发抢占——要么是池内空闲容量不足要么是某条策略规则阻止了授予。此时调和器可能将若干已运行的请求标记为抢占这会取消这些 step 运行并将它们的容量归还给池。谁可以被停止只有preemptibleTrueResourceSettings中的默认值的 step 才可能成为被抢占的候选。preemptibleFalse的含义是永远不要选择这个运行作为被牺牲的对象。谁先被停止简单视角低策略优先级优先在同一池内的可抢占运行中较低策略优先级policy priority先于较高优先级被考虑。如果等待作业的优先级严格高于某个候选受害者的优先级则该受害者可以被抢占以腾出空间——前提是释放它确实能解决容量短缺。reserved 引入回收reclaim概念如果等待组件在该池上仍有未使用的 reserved 余量reserved 减去它当前已使用的部分系统可以抢占那些正在使用借用borrowed容量的可抢占运行——即使这些运行的优先级与等待者相同甚至更高。直觉是你的 reserved 份额是属于你的如果别人占用了本可以由你的预留覆盖的空闲容量他们可以被移开。limit 不参与选择受害者limit 只限制组件最多可以持有多少如果等待请求自身超过了它的 limit杀死其他作业也无济于事——此时你需要更高的 limit 或更小的请求。受害者按策略优先级升序排序并以分配时间作为平局决胜tie-break。Step 级参数preemptible设置效果preemptibleTrue默认该运行可能被抢占以帮助其他请求。preemptibleFalse该运行永远不会被抢占。每个池键的请求量必须 ≤ 该键在策略中的reserved高于 reserved 的limit不会提高不可抢占 step 的请求上限。策略不会覆盖preemptible标记策略只影响允许被抢占的运行之间的排序与回收关系。抢占之后被抢占的 step 运行会停止资源释放回池中step 回到队列并再次重试。如果重试次数耗尽或 step 未配置重试step 失败。在 src/zenml/config/resource_settings.py 中还有一个值得注意的细节ResourceSettings.empty属性会排除preemptible与pool_resources——这两个字段仅与资源池调度相关当前被 orchestrator 和 step operator 等负载调度组件忽略。这意味着preemptible和pool_resources是纯资源池语义字段不会影响传统的工作负载资源请求。策略场景reserved、limit 与 preemptible 如何交互理解了三者的定义reserved记账归属份额、limit硬上限、priority排队/抢占优先级详见 核心概念文档下面给出原文档总结的四类典型场景公平份额 突发Fair Share Plus Burst将reserved设为你希望记账归属的份额将limit设为该 stack 最多能持有的量。可抢占step 可以在池有空闲时借用reserved 与 limit 之间以及不超过池总量的空闲容量。不可抢占step 无论 limit 多高每个请求键最多只使用reserved。生产 vs 实验Production vs Experiments给生产策略设置更高的priority。实验 step 保持preemptible这样生产作业既能抢占容量也能在需要其预留份额时回收实验作业借用的余量。不可抢占的训练作业Non-Preemptible Training设置preemptibleFalse并将reserved调整到满足每个 step 的每键请求例如gpu_count≤ 该键的 reserved。limit可以为同一策略上的可抢占突发设得更高但它不会提高不可抢占请求的上限——如果这些作业每 step 需要更多必须提高reserved。调和器还会阻止那些坐落在借用容量上、且可能与其他不可抢占使用冲突的不可抢占授予。一个组件对应多个池Several Pools for One Component为不同池配置多条带不同priority的策略排队与分配时更高优先级更受青睐但要受每个池limit的约束。服务器按优先级尝试各池先授予成功的池拥有该分配其余池中的队列条目会被作为过期项丢弃。这适合主备primary/fallback或区域性容量场景而非把单 step 的需求拆分到多个配额中参见 示例——多池与多键请求。从需求到分配源码与文档互相印证的调度链路综合本文涉及的文档与源码一条完整的调度链路可以这样概括声明需求step 作者在step(settings{resources: ResourceSettings(...)})中声明gpu_count、cpu_count、memory、pool_resources与preemptible。文档中的完整可运行示例见 资源池总览其中包含pipeline(dynamicTrue)的动态流水线声明。生成请求服务器在 step 启动时调用merged_requested_resources()把强类型字段转为gpu/mcpu/memory_mb/自定义键并追加step_run: 1连同preemptible一起持久化为资源请求sql_zen_store.py。逐池评估资格每个候选池针对完整请求评估——mcpu、memory_mb、step_run三种内置键若在池中缺行则视为无界不会因此拒绝其余键包括gpu和pool_resources自定义键缺行即零容量正数请求会被拒绝。若策略定义了键但策略未配置则 limit 回退到池总量、reserved 默认为 0——此时不可抢占 step 的任意正数请求都会被拒绝详见核心概念文档。排队与分配容量不足则入队客户端带退避轮询调和器按优先级与 reserved 余量挑选授予对象。抢占回收队列头部无法授予时按低优先级优先、reserved 回收、limit 不选受害者的规则选择可抢占受害者释放容量。失败兜底请求超过池总量或策略 limit 时立即拒绝不排队被抢占且重试耗尽则 step 失败运行结束后资源归还。结论ZenML Pro 的资源池调和机制用三个参数reserved、limit、priority和一个 step 级开关preemptible实现了严格保障与弹性共享可兼得的调度模型不可抢占作业在 reserved 范围内获得确定性保障可抢占作业可以借用空闲容量换取更高的吞吐与硬件利用率而优先级与回收规则确保了生产作业在竞争时能拿回属于自己的份额。理解本文所述的运行时六阶段流程与抢占裁决顺序是正确配置多团队共享 GPU 池、避免作业被莫名杀死或容量闲置浪费的前提。延伸阅读资源池总览产品视角与使用场景核心概念池、策略、请求的精确定义示例工作簿pool/policy/ResourceSettings 与结果的完整演练在 Kubernetes 上启用资源池调和器微服务ResourceSettings源码实现src/zenml/config/resource_settings.py资源请求的服务端创建逻辑src/zenml/zen_stores/sql_zen_store.py【免费下载链接】zenmlZenML : One AI Platform from Pipelines to Agents. https://zenml.io.项目地址: https://gitcode.com/GitHub_Trending/ze/zenml创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考