尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Kubernetes、Ray、vLLM 三层调度拆解:从 Pod 到 Task 再到 Sequence

发布时间:2026/9/29 18:45:45

资讯中心
01
ARTICLE

Kubernetes、Ray、vLLM 三层调度拆解:从 Pod 到 Task 再到 Sequence

Kubernetes、Ray、vLLM 三层调度拆解:从 Pod 到 Task 再到 Sequence
Kubernetes、Ray、vLLM这三个名词放在一起做大模型基础设施的人几乎天天见。但你要是随手抓一个正在部署 DeepSeek 的同学问问三者的“调度”到底分别管什么很可能得到一段含糊其辞的回答甚至有人说“我全用 K8s 调度了为什么还要搞 Ray”。我过去一年帮团队搭过不止一套大模型推理服务自己也踩过不少把三层调度混在一起理解才踩的坑所以这篇就把三者的边界彻底掰开揉碎讲清楚。先把结论放在最前面方便你带着结论往下看Kubernetes 调度的是 Pod决定一个容器跑到哪台物理节点上Ray 调度的是 Task 和 Actor决定分布式计算任务放到哪个进程里执行vLLM 调度的是 Sequence决定显存里哪些请求的哪些 token 参与下一步计算。这三层不是竞争关系而是堆叠关系。下面我每一层都拆开讲它调度什么、依据什么决策、常见坑在哪最后用一个多机推理服务的真实案例把三者串起来。1. 先搞清楚一件事调度到底在调什么1.1 用餐厅类比理解三层调度很多人一说“调度”就想到“排队”“分配资源”这个直觉没错但三层系统的“资源”根本不是同一个东西。我习惯用餐厅来类比Kubernetes 是物业管理层。它决定一家店开在哪层、桌椅摆哪些区域、包间怎么划分。对应到技术里就是决定 Pod 放到哪台服务器上关心的是 CPU、内存、GPU、网卡、磁盘这些硬件资源。K8s 调度器只关心“盒子”放到哪个物理位置最合适盒子里面的业务流程它一概不管。Ray 是后厨的工序管理。订单来了以后后厨经理决定哪道菜给哪个灶台做哪些菜可以并行哪些必须等前置工序完成。对应到技术里就是分布式任务怎么拆、Actor 放在哪、资源组怎么组合。它关心的是“逻辑资源”和“数据局部性”比如张量并行的 8 个进程必须落在网络互通的节点上。vLLM 是前台的领位员。一张餐桌明明坐不下太多客人但通过翻台和拼桌尽可能同时接待更多顾客。对应到技术里就是让一批请求尽量挤进同一个 GPU 的显存决定谁先上、谁让位、谁排到下一轮。它关心的是 KV Cache 块和响应延迟之间的取舍。这个类比帮不少人理清了困惑K8s 调度的结束恰好是 Ray 调度的开始Ray 把进程安排好了vLLM 才开始在进程内部调度请求。1.2 为什么一个大模型项目要同时用上三层调度单机跑一个小模型确实只需要 vLLM 就够K8s 都可以不要docker run 就完事。但生产环境一旦面对几百亿甚至上千亿参数的大模型情况完全不同模型权重超过单卡显存必须做多机张量并行那就需要一组进程协同工作推理、训练、数据预处理任务经常混部在同一批 GPU 节点上机器层面的资源隔离必须交给集群系统面对高并发请求单张 GPU 内要同时处理几十上百个序列引擎内部必须有自己的请求调度机制。这三层问题分别发生在物理机、分布式任务、显存内部所以才会出现三个独立的调度器。最需要记住的一点是它们调度的对象完全不同所以不存在谁替代谁的问题只存在怎么配合的问题。2. Kubernetes 调度器决定 Pod 落到哪台机器2.1 kube-scheduler 的决策流程过滤、打分、绑定K8s 默认的 kube-scheduler 是一个控制循环核心流程三步过滤Filtering、打分Scoring、绑定Binding。过滤阶段把所有不满足条件的节点排除掉。比如 Pod 声明需要nvidia.com/gpu: 1那没有 GPU 的节点直接出局节点上有污点taint而 Pod 没有对应容忍度toleration也直接出局端口冲突、nodeSelector 不匹配、affinity 不满足都会在这一步被淘汰。打分阶段对剩下的节点排序。默认的打分插件会综合考虑节点剩余资源是否充足、镜像是否已经在节点上镜像本地性、节点亲和性和 Pod 间亲和性等。实际表现就是剩余资源越均衡、镜像本地越有利的节点得分越高。绑定阶段把 Pod 写入选中节点的调度结果然后 kubelet 再真正把容器拉起来。我给团队排障时见过最多的 Pending 场景就是资源其实够但节点有污点。很多同学不知道要给 GPU 节点打个专用污点结果 CPU 任务和 GPU 任务挤在一起到了真正需要 GPU 的 Pod 调度时反而因为没有容忍度一直卡在待调度队列里。2.2 大模型场景下最常用的几个调度约束大模型服务部署时常用的调度约束其实就那么几个但组合起来效果差异很大。第一个是节点标签和亲和性。GPU 型号决定你能跑多大的模型所以通常会按nvidia.com/gpu.product给节点打标签A100、H100、L20 分开。然后 Pod 用nodeSelector或nodeAffinity精确选到对应型号的节点。第二个是污点和容忍度。GPU 节点上打nvidia.com/gputrue:NoSchedule之类的污点只让显式声明容忍度的推理服务 Pod 上来避免日常业务容器占用宝贵的 GPU 机器。第三个是拓扑分布约束topologySpreadConstraints。如果你有 20 个副本默认打分会尽量把它们打散到不同节点这本来是好事但对分布式训练或张量并行推理来说你需要的是相反效果——把多个关联 Pod 聚到同一个节点或同一个机架减少跨机通信。这时候要明确用podAffinity或者 Ray 的 Placement Group 来做聚合。2.3 K8s 调度器决定不了什么K8s 调度器把 Pod 绑定到节点之后它的职责就结束了。它不关心 Pod 里的进程之间怎么通信不关心 vLLM 当前有没有在处理请求更不关心 GPU 利用率是高是低。这个边界不清是很多性能排查走弯路的总根源。我一个真实的经历同事反馈“K8s 起来了 4 个 vLLM Pod但 GPU 利用率一直上不去”。查了半天发现问题根本不在 K8s而是 vLLM 部署时--max-num-seqs设得太小并发请求全在排队GPU 每步只算一点点活。K8s 看 Pod 是 RunningvLLM 看队列是满的但实际吞吐就是上不来。这种情况你在 K8s 调度器层面怎么调参数都没用得去引擎层看。另一个常见的现象是“Pod 调度成功了一启动就显存 OOM”。原因也很典型K8s 调度 GPU 是按整卡来它不知道进程实际吃掉多少显存。你一个 Pod 请求了 1 张 80G 的卡结果 vLLM 配置的gpu_memory_utilization是 0.98把显存几乎占满节点上其他 Pod 一启动总显存就爆了。K8s 层面没有任何机制能阻止这种超卖只能靠你在调度策略上做隔离或者给真正常驻的推理 Pod 留足余量。3. Ray 调度器决定 Task 和 Actor 跑到哪个进程3.1 Ray 的资源模型和调度对象Ray 是分布式计算引擎它对“资源”的定义比 K8s 更灵活。用户给ray.remote标注资源需求比如ray.remote(num_gpus1)Ray 调度器收到一个 Task 或 Actor 时会在集群范围内找一个满足资源条件的节点再把任务发到那个节点的 raylet 进程上执行。Ray 的调度对象有三类Task无状态的远程函数执行完就结束适合数据处理、预处理这类任务Actor有状态的远程对象常驻在某个节点适合承载 vLLM Engine 这类需要保持状态的进程Placement Group一组资源的预订类似“我要在同一个节点上预留 8 张 GPU”然后往里放多个 Task 或 Actor。这里特别要说一下 Placement Group。多机张量推理时8 个进程需要高强度互相通信最好落在同一个节点或者至少同一个机架。K8s 调度 Pod 是一个一个来的它本身没有“把这一批 Pod 一起调度到关联位置”的原生能力但 Ray 的 Placement Group 可以做到先整体锁定资源再把多个 Actor 放进去保证 locality。3.2 Ray 调度与 K8s 调度的核心差异差异主要体现在三个维度调度对象、调度时机、资源组合方式。维度KubernetesRay调度对象PodTask / Actor / Placement Group调度时机Pod 创建时一次决定每次提交任务都可能调度毫秒级资源单位容器可声明的 CPU、内存、GPU自定义逻辑资源比如 GPU 可以只申请 0.5生命周期Pod 启动后长期存在Actor 可常驻可销毁Task 用完即走位置约束nodeSelector、affinityplacement group、strategy、拓扑感知最关键的一点是Ray 可以一个 Pod 内部调度多个 Actor。也就是说 K8s 给 Ray 集群准备了 10 个 worker Pod每个 Pod 有 8 张 GPURay 调度器可以在这些 Pod 上灵活放置几十个 Actor按任务实际需求分配 GPU而不是一个 Pod 只能跑一个固定进程。当然这种灵活性也是有代价的如果一个 worker Pod 挂了上面所有 Actor 都得重建如果 Ray 不知道某个节点上还有别的租户在占显存它的资源统计就会失真。所以生产环境用 KubeRay 这类 Operator 把 Ray 集群固定在 K8s 里时最好让一个 worker Pod 只对应一种资源规格别混部。3.3 为什么多机大模型推理偏偏需要一个 Ray 层很多人第一次接触 Ray 是在 vLLM 的多机部署文档里。vLLM 本身支持张量并行但当你需要跨多台机器时就需要一个机制把不同 rank 的进程拉起并让它们互相知道对方地址。Ray 就是这个机制。具体流程通常是在一个 Ray 集群上vLLM 用 Ray Actor 的方式启动多个 worker每个 worker 负责一个 rank通过 Ray 的 object store 或者直接通过 NCCL 做通信。你可以用 vLLM 的--ray-workers之类的配置也可以自己写一个脚本在每个 Actor 里 import vLLM 并初始化引擎。这里就牵扯到和 K8s 的配合KubeRay Operator 负责把 head 和 worker 的 Pod 建出来K8s 保证每个 Pod 都能分配到对应的 GPUPod 起来之后Ray 调度器接管决定 vLLM 的每一个 rank 进程放在哪个 Pod 上。K8s 管的是 Ray 集群的节点Ray 管的是节点上跑什么任务。这个分工想清楚了下面 vLLM 的调度就好理解了。4. vLLM 调度器决定请求何时进入显存计算4.1 vLLM 调度的是 Sequence不是一个 HTTP 请求vLLM 对外看起来是一个 OpenAI 兼容的 HTTP 服务但内部调度的单位从来不是“请求”而是Sequence——一个请求对应的完整 token 序列。当你发一个文本生成请求vLLM 的 tokenizer 会把它编码成一组 token然后变成一个 Sequence 对象交给 scheduler 管理。此后这个 Sequence 会经历几个状态WAITING等待被调度进入 GPU 计算常见原因是当前显存里的 KV Cache 块不够RUNNING正在参与前向计算每个 decode step 都在消耗 KV Cache 块SWAPPEDKV Cache 被换出到 CPU 内存或磁盘GPU 空间被让给其他 Sequence。这个状态机是 vLLM 调度的核心。vLLM 的调度器本质上是一个“显存块分配器”它把 GPU 显存预先划分成固定大小的物理块block每个 Sequence 按需申请逻辑块逻辑块再映射到物理块。你问“这条请求什么时候开始算”答案不取决于 API 服务器而取决于 scheduler 能不能给这个 Sequence 分到足够的物理块。4.2 Continuous Batching 是 vLLM 调度器的灵魂如果不用任何批处理GPU 一次只处理一个请求吞吐会低到没法看。简单的动态批处理是等一批请求凑齐再一起算这在所有请求长度相近时还行但一旦有长请求拖后腿其他短请求只能干等。vLLM 的核心竞争力是Continuous Batching也叫持续批处理。它的思路是不再把“批”当作一个固定的集合而是每个 decode step 都重新决定接下来把哪些 Sequence 拼成一个 batch 送进 GPU。具体来说vLLM 的 scheduler 每个 step 会执行一次调度决策检查当前 RUNNING 的 Sequence 哪些还活着没结束、没被抢占从 WAITING 队列中挑选尽可能多的新 Sequence尝试给它们分配显存块分配成功的加入本轮计算把选中的所有 Sequence 的 token ID 拼成一个 batch交给 executor 做前向传播前向结束后把每个 Sequence 的新 token 更新回去释放结束或超时的 Sequence 占用的块。这就是为什么 vLLM 能“随到随算”一个请求只要显存有位置下一轮 decode 就能被塞进去不用等整个批次结束。我之前在七牛内部做压测时把大批短请求和几个超长请求混在一起动态批处理的 TPOT每个 token 的生成时间会随着长请求波动而 continuous batching 明显更平稳。4.3 EngineCore 与 Scheduler、Executor 的交互流程新版本 vLLM 的架构里常听到EngineCore这个概念。它是 vLLM 的异步引擎核心内部包含了两个关键组件Scheduler 和 Executor。Scheduler是决策大脑。它维护 Sequence 的状态、管理物理块分配、决定本轮 batch 由哪些 Sequence 组成。它不直接跑 GPU kernel只负责“规划”。Executor是执行手臂。它接收 scheduler 的规划结果真正把 token 数据拷到 GPU调用 PagedAttention 这些 kernel 做前向再把输出返回给 scheduler。交互流程大致是API 前端收到新请求把它交给 EngineCoreEngineCore 内部的 scheduler 把请求转成 Sequence尝试为它分配逻辑块和物理块Scheduler 生成一个调度计划scheduling plan里面是一组要参与计算的 token 和相关元数据Executor 拿到计划后在指定模型 worker 上执行前向计算Executor 返回每个 Sequence 的输出 tokenscheduler 更新状态和块映射继续下一轮。多机张量并行时这个 Executor 内部还会再拆分每个 rank 一个 worker通过 NCCL 通信。而如果这些 worker 是通过 Ray 启动的那 vLLM 内部的 executor 调度又会和 Ray 的 actor 调度产生交互。所以你在排查日志时经常会同时看到 vLLM scheduler 的日志、Ray actor 的日志、以及 K8s Pod 的事件三层日志交织在一起必须清楚各自在说什么。4.4 V0/V1 调度器变化带来的性能差异vLLM 社区这两年有一个大变化从 V0 调度器演进到 V1 调度器。V1 改进了调度流水线把 prefill预填充和 decode解码的调度策略统一起来对前缀缓存prefix caching的处理更积极也让整个执行流程更可预测。我实际测试下来V1 在长上下文、高并发场景下通常吞吐更好但在某些小模型、短请求为主的场景新版本的调度开销反而让延迟略微上升。所以网上一搜“vLLM 新版本性能下降”大概率不是 bug而是默认调度器变了请求模式不匹配。排查思路很简单先确认你用的是哪个 vLLM 版本再看是否默认启用 V1然后根据请求特征决定要不要保留 V1 或者关掉它。有些模型厂商的官方文档会明确要求某个 vLLM 镜像版本比如已有的 GLM 系列部署指引就会指定镜像 tag这种时候就别乱升版本老老实实按厂商验证过的组合来。5. 三层调度如何协作一个 DeepSeek 类大模型的部署案例5.1 从用户请求到 GPU 上的一次前向传播我把一个真实项目里的部署案例简化一下作为三层调度的完整说明。假设要部署一个参数量很大的 MoE 模型单卡放不下必须用 8 张 GPU 做张量并行。整个系统链路是这样的用户在客户端比如 Chatbox发出一条消息请求打到 vLLM 的 OpenAI 兼容接口vLLM API 层用一个 Ray Actor 作为 engine worker 的调度入口Ray 调度器根据 Placement Group 的配置把 8 个 worker Actor 分别放到不同的 worker Pod 上每个 Actor 里初始化一个 vLLM engine 实例负责各自 rank 的模型分片这 8 个 worker Pod 由 KubeRay Operator 交给 KubernetesK8s 调度器保证每个 Pod 都能分配到对应节点上的 8 张 GPU 之一用户请求在 vLLM 引擎内部被 tokenizer 转成 Sequencescheduler 为它分配 KV Cache blockexecutor 在 8 张 GPU 上做并行前向NCCL 负责进程间通信生成完成后token 流经 vLLM API 返回给用户。你看一个请求从发出到返回正好穿透了三层调度K8s 决定 Pod 在哪台机器Ray 决定 engine worker 在哪个进程vLLM 决定这个 Sequence 何时进入显存计算。5.2 三层各自的决策内容和失败表现层级调度对象核心决策失败表现KubernetesPodPod 绑定到哪个节点是否满足 CPU/内存/GPU 约束Pod Pending事件里报资源不足或污点不匹配RayTask / Actor / Placement Group计算任务运行在哪个 worker 进程多个进程如何组合任务提交后一直等调度日志显示资源不可用vLLMSequence / KV Cache block哪些 Sequence 进入下一轮计算分配多少显存块请求超时、TTFT 升高、GPU OOM、preempt 频繁这张表我建议你直接保存在手边。排障的时候先看现象落在哪一层再去查对应层的日志和指标能省去大量无效排查时间。5.3 层间不协调的典型翻车现场三层系统最大的麻烦在于每一层都有自己的“视图”视图之间会失真。我至少见过三种典型的翻车第一种是K8s 给了 GPU但 Ray 不认。K8s 的 worker Pod 里如果环境变量和资源声明对不上Ray 可能认为该节点只有 0 张 GPU于是 vLLM 的张量并行任务一直卡在等待资源。报错往往是 “ResourceUnavailable” 或者 GPU 数量不足但你在 K8s 看节点明明有 GPU。解决办法是在 Pod spec 里正确声明nvidia.com/gpu资源并确保 Ray 的资源配置和物理环境一致。第二种是Ray 认为有资源但显存撑不住。Ray 只统计“有多少张 GPU”它不关心每张 GPU 里的显存是否还够用。两个 Actor 各自申请了 1 张 80G 的 GPU但模型权重加 KV Cache 加起来要 160G于是第二个 Actor 一启动就 OOM。这种问题只能靠部署规划来避免给 vLLM 的gpu_memory_utilization留出足够的 margin别把显存用得太满。第三种是vLLM 和 K8s 对“健康”的定义不一致。K8s 判断 Pod 健康看的是探针是否通过vLLM 判断健康看的是引擎是否 ready。有时 K8s 探针配置得太宽松vLLM 因为显存压力进入半死状态K8s 还在把流量往里打导致线上超时率飙升。所以我通常会建议把 readiness 探针做成真正的 vLLM 就绪接口而不是一个简单的 TCP 连接检查。6. 常见误区与性能排查实录6.1 三层调度速查表对号入座这一节把我平时被问得最多的问题整理成速查表配合上面的内容大部分困惑都能对号入座问题真正的答案“vLLM 是不是自带调度不需要 K8s”vLLM 调度的是显存内的请求序列K8s 调度的是机器上的容器。单机可以不用 K8s多机必须配合。“Ray 和 K8s 哪个更好”不是同一个层面的东西。Ray 跑在 K8s 之上K8s 提供机器资源Ray 提供分布式任务调度。“为什么我调大了 max-num-seqs 反而变慢”并发序列太多KV Cache 块不足scheduler 频繁抢占和换出性能反而恶化。“vLLM 新版本性能下降怎么定位”先确认 V1/V0 版本差异再看 TTFT 和吞吐是两个维度最后排查 max-num-seqs 和 gpu_memory_utilization。“docker 镜像里带模型吗”官方的 vLLM 镜像基本不带模型权重权重要靠挂载目录加载。很多人第一次用 docker 部署时在这里踩坑。6.2 vLLM 性能下降的排查思路如果你的 vLLM 明明升级了大版本但压测结果反而退步我建议按这个顺序排查先确认版本组合。不同模型对不同 vLLM 版本的要求不一样。尤其是一些大模型厂商会在部署文档里明确指定验证过的 vLLM 镜像 tag比如某个 GLM 系列模型的官方部署指引就锁定了特定版本镜像。这种情况下别自作主张升到最新版稳定优先。把指标拆开看。首 token 延迟TTFT和总吞吐是两件完全不同的事。V1 调度器在有些场景下会优先保证吞吐但代价是某些请求的 TTFT 轻微上升。如果用户只感受到“变慢了”你得先判断是变慢在首 token还是整体生成速度下滑。检查调度队列状态。vLLM 的指标里会暴露 waiting 和 running 队列长度。如果 waiting 长时间非空说明显存块不够如果 swapped 频繁说明抢占太严重。这时候要调的不是 vLLM 线程数而是max-num-seqs和gpu_memory_utilization的平衡。拿 benchmark 说话。vLLM 自带 benchmark 脚本固定一个请求长度和并发数别用随意的手工对话来做判断。同样的配置跑两轮一轮是旧版镜像一轮是新版镜像输出对比数字再做结论。顺便说一句很多人拿 sglang 和 vLLM 对比。sglang 的 RadixAttention 在前缀复用场景下有独特优势如果你们的请求有大量的共享系统提示词或长文档前缀值得评估但 vLLM 的生态更成熟第三方框架兼容性更好。两者互有胜负没有绝对最优。6.3 技术选型建议与我的个人经验最后分享一组我实际用下来的选型建议纯个人经验供你参考如果模型能在单卡上跑直接 vLLM 起服务配合 K8s 做副本伸缩就够了不需要 Ray。引入 Ray 只会增加一层复杂度。如果模型需要多机张量并行优先考虑 KubeRay 加 Ray。K8s 管 Pod 生命周期Ray 管引擎进程调度分工明确。如果只是想在本地 Windows 上做实验docker 跑一个 vllm-openai 镜像就够别在生产环境折腾 Windows 下的 GPU 支持生态和性能都吃亏。如果要用 docker 部署 vLLM记住一件事镜像只是运行环境模型权重必须挂载进容器。我第一次用 docker 部署时以为镜像自带模型结果容器起来了模型加载却一直报路径不存在白白折腾了半天。我自己踩过最深刻的坑是在一个训练推理混部项目里K8s 的 worker Pod 只声明了 CPU 和内存限制GPU 是通过环境变量传给容器的结果 Ray 调度器报告“节点有 0 张 GPU”所有推理任务全部堆积。后来把nvidia.com/gpu显式写进 Pod 的资源 limits问题立刻消失。这件事让我彻底明白三层调度系统里任何一层的资源视图失真是可能的排障时永远要回到“我到底在哪一层看问题”这个原点。如果你现在正在折腾 vLLM 多机部署或者被 Ray 的调度日志搞得一头雾水我建议你先把这篇文章里的速查表存下来遇到问题先对号入座往往能少走一半弯路。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。