ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SkyPilot Sky Serve 架构与实战:从单一 Endpoint 到跨云多副本弹性推理服务

SkyPilot Sky Serve 架构与实战:从单一 Endpoint 到跨云多副本弹性推理服务 SkyPilot Sky Serve 架构与实战从单一 Endpoint 到跨云多副本弹性推理服务【免费下载链接】skypilotThe AI Compute Platform for frontier teams. SkyPilot turns fragmented AI compute into one AI supercomputer, so frontier AI teams build custom intelligence faster.项目地址: https://gitcode.com/GitHub_Trending/sk/skypilotSky Serve 是 SkyPilot 内置的推理服务托管库位于 sky/serve 目录其目标非常直接对外暴露一个稳定的 Endpoint把进入的流量透明地分发到运行在不同资源、不同区域、甚至不同云厂商上的多个服务端点副本上。负载均衡Load Balancing、故障转移Failover与弹性伸缩Autoscaling全部由 Sky Serve 在后台自动处理用户只需要提交一个声明式的 Service YAML。读完本文你将掌握 Sky Serve 的四组件架构、Service YAML 的完整配置语义、请求级负载均衡与 QPS 驱动的自动扩缩容原理并能用sky serve命令一键部署并运维一个多副本推理服务。设计目标一个 Endpoint任意规模的服务集群在 SkyPilot 的定位中前端团队的计算往往横跨多个云厂商、多个区域还可能同时使用按需实例与 Spot 实例。传统做法需要自己搭建网关、写健康检查、处理实例被抢占时的迁移——工作量大且极易出错。Sky Serve 把这些复杂性收敛为一个用户感知不到的服务层暴露一个 Endpoint将任何进入的流量分发到运行在不同资源、区域和云上的服务端点。它透明地处理了三大核心问题负载均衡把请求均匀或按策略地分到健康副本、故障转移副本失败时自动把流量切到其他健康副本并重建新副本、自动伸缩根据流量或队列长度动态增减副本数量。这意味着用户可以把 Spot 实例的抢占、某个区域容量不足、甚至整个云不可用都交给系统兜底服务对外始终只有一个稳定的 URL。四组件架构总览Sky Serve 的核心架构由四个关键组件构成架构图见 docs/source/images/sky-serve-architecture.pngLoad Balancers负载均衡器接收所有进入的请求按照所选策略把请求代理转发到健康副本。实现位于 sky/serve/load_balancer.py。Load Balancing Policies负载均衡策略定义请求如何在健康副本之间分布例如轮询、最少负载等。实现位于 sky/serve/load_balancing_policies.py。Autoscalers自动伸缩器根据流量指标QPS、队列长度等动态决定副本的扩缩。实现位于 sky/serve/autoscalers.py。Replica Managers副本管理器负责副本的创建、销毁、健康探测与故障恢复。实现位于 sky/serve/replica_managers.py。四个组件共同运行在一个名为Controller的常驻进程中由sky serve up自动在云端拉起。Controller 负责协调一切它维护服务与副本的元数据数据库sky/serve/serve_state.py 中的services、replicas、version_specs三张表调度 Replica Manager 执行副本的sky.launch/sky down并驱动 Autoscaler 周期性产出扩缩容决策。负载均衡器如何工作同步 代理 重试load_balancer.py 中的SkyServeLoadBalancer是一个基于 FastAPI Uvicorn 的异步代理进程每LB_CONTROLLER_SYNC_INTERVAL_SECONDS 20秒与 Controller 同步一次_sync_with_controller拉取当前健康副本列表同时把这一周期内累计的请求时间戳上报给 Controller供 Autoscaler 计算 QPSconstants.py。每个请求进入_proxy_with_retries先由策略从健康副本中选出一个 URL再用httpx.AsyncClient以流式方式代理请求_proxy_request_to响应通过自定义的_CleanupStreamingResponse边收边转发。由于支持 Spot 实例上的推理副本可能在请求处理途中被抢占因此代理内置了最多LB_MAX_RETRY 3次重试无可用副本时返回 503客户端中途断开返回 499重试耗尽返回 500load_balancer.py。流式响应的默认超时为 120 秒足够覆盖 Llama2-70B 这类大模型的一次生成。Service YAML 配置全解析Sky Serve 的配置入口是 Service YAML核心是service:段。解析与校验逻辑全部集中在 sky/serve/service_spec.py 的SkyServiceSpec.from_yaml_config。以下以一个真实的 vLLM 服务为例完整文件见 examples/serve/vllm.yamlservice: readiness_probe: path: /v1/models initial_delay_seconds: 1200 # vLLM 安装需要 5-10 分钟 replicas: 2 resources: ports: 8081 accelerators: A100:1 setup: | conda activate chatbot ... run: | conda activate chatbot python3 -m fastchat.serve.openai_api_server --host ${HOST_IP} --port 8081readiness_probe健康探测配置readiness_probe既可以是字符串等价于path也可以是完整字典service_spec.py配置项含义默认值path就绪探测的 HTTP 路径必须以/开头必填initial_delay_seconds服务启动后此期间内的探测失败被忽略用于等待模型加载/依赖安装1200timeout_seconds单次就绪探测请求的超时时间15endpoint_probe_interval_seconds探测副本端点的间隔10post_data以 POST 方式探测时携带的 JSON 请求体None默认 GETheaders探测时附加的自定义请求头Noneconsecutive_failure_threshold_timeout连续失败达到该超时后判定副本失败None这些默认值均来自 sky/serve/constants.py。initial_delay_seconds默认 1200 秒是因为真实 LLM 推理服务的就绪探测往往要等模型权重加载与依赖安装过早判定失败会导致副本被误杀。副本策略replica_policy / replicasservice:段中副本数量既可以用简写replicas: 2等价于固定 2 个副本也可以用完整的replica_policy:二者不能同时出现见 service_spec.pyservice: replica_policy: min_replicas: 1 max_replicas: 4 target_qps_per_replica: 2.0 # 触发自动伸缩的每副本目标 QPS num_overprovision: 0 # 在目标副本数之上额外多起的副本数 upscale_delay_seconds: 300 # 扩容生效前的持续观察时间 downscale_delay_seconds: 1200 # 缩容生效前的持续观察时间 base_ondemand_fallback_replicas: 1 # 常驻的按需实例副本数 dynamic_ondemand_fallback: false # 抢占后是否动态补按需实例关键校验规则service_spec.py设置target_qps_per_replica时必须同时设置max_replicas未设置target_qps_per_replica时min_replicas与max_replicas必须相等固定副本数max_replicas不得小于min_replicas。load_balancing_policy 与负载均衡策略注册表load_balancing_policy字段用于选择流量分发策略。load_balancing_policies.py 通过LoadBalancingPolicy.__init_subclass__机制把策略自动注册进全局LB_POLICIES注册表未知策略名会在 YAML 解析阶段直接报错service_spec.py。当前可用的策略策略名行为默认least_load最少负载实时跟踪每个副本的在途请求数优先选择负载最小的副本并轮转打破平局✅ 默认round_robin轮询副本列表变化时先随机打乱避免第一个副本长期承接最多流量instance_aware_least_load实例感知最少负载按副本 GPU 型号的target_qps_per_replica归一化负载后再选择round_robin的实现尤其值得注意set_ready_replicas在副本集合变化时先random.shuffle再重置指针load_balancing_policies.py这是为了防止 Autoscaler 反复扩缩容导致排在最前的副本总是承接最多请求。实例感知策略异构 GPU 集群的按能力调度当target_qps_per_replica是字典按 GPU 型号给出不同目标 QPS时必须配合load_balancing_policy: instance_aware_least_load使用否则 YAML 校验失败service_spec.pyservice: replica_policy: min_replicas: 1 max_replicas: 4 target_qps_per_replica: A100: 2.0 H100: 4.0 load_balancing_policy: instance_aware_least_loadInstanceAwareLeastLoadPolicy会把每个副本的当前负载除以该副本 GPU 型号对应的目标 QPS得到归一化负载后再取最小者load_balancing_policies.py并对A100:1这类带数量后缀的型号做基名匹配A100:1匹配A100。匹配不到时使用默认值 1.0 作为兜底避免除零。对应地Autoscaler 也会切换为InstanceAwareRequestRateAutoscalerautoscalers.py扩容时按最快的 GPU 的 QPS 估算所需副本数缩容时优先回收 QPS 能力最低的副本。端口与 TLSports副本对外暴露的端口必须处于 1-65535 之间service_spec.py同时需要在resources.ports中声明。tls提供keyfile与certfile后负载均衡器将升级为 HTTPS 端点load_balancer.py证书通过TLSCredential.dump_uvicorn_kwargs()直接注入 Uvicorn。自动伸缩QPS 驱动与队列长度驱动Autoscaler 位于 sky/serve/autoscalers.py由Autoscaler.from_spec根据配置自动选择实现autoscalers.py配置了pool→QueueLengthAutoscaler队列长度驱动配置了use_ondemand_fallback→FallbackRequestRateAutoscalerQPS 驱动 Spot/按需兜底target_qps_per_replica为字典 →InstanceAwareRequestRateAutoscaler其他 →RequestRateAutoscaler标准 QPS 驱动。决策模型与滞回Hysteresis所有基于 QPS 的 Autoscaler 都继承自_AutoscalerWithHysteresis。核心思想是不因为单次波动就扩缩容而是要求目标副本数在连续多个决策周期内持续偏离当前值才生效决策间隔默认 20 秒当目标副本数为 0min_replicas: 0且无流量时缩短到 5 秒加快服务拉起autoscalers.py。扩容阈值 upscale_delay_seconds / 20默认 300 秒 → 需要连续 15 个周期约 5 分钟都要求扩容才真正扩容缩容阈值默认 1200 秒 → 约 20 分钟。有一个快速通道当前目标副本数为 0 时立即采用新目标避免冷启动延迟autoscalers.py。RequestRateAutoscaler._calculate_target_num_replicas的算法非常直观用最近 60 秒窗口内的请求时间戳数量除以窗口长度得到每秒请求数再除以单副本目标 QPS 后向上取整最后裁剪到[min_replicas, max_replicas]区间autoscalers.py。请求时间戳由负载均衡器每 20 秒上报一次Autoscaler 用bisect维护滑动窗口。Spot 与按需兜底FallbackRequestRateAutoscaler在 QPS 伸缩之上叠加了 Spot 策略autoscalers.pybase_ondemand_fallback_replicas始终保留 N 个按需实例提供基本的可用性保证dynamic_ondemand_fallback任何 Spot 副本被抢占就用按需实例动态补位按num_ready_spot而非num_nonterminal_spot计算缺口因为被抢占的 Spot 可能永远无法恢复。扩容时 Spot 与按需分别通过SPOT_OVERRIDE {use_spot: True}与ONDEMAND_OVERRIDE {use_spot: False}资源覆盖来下发autoscalers.pyReplica Manager 在launch_cluster中把这些覆盖应用到每个副本的sky.Task资源上replica_managers.py。副本的缩容优先级需要缩容时_select_nonterminal_replicas_to_scale_down按四重标准排序autoscalers.py状态越早期越先缩PENDING → PROVISIONING → STARTING → NOT_READY → READY见 serve_state.py版本号小的旧版本先缩对 Pool 场景运行作业数少的空闲 worker 先缩副本 ID 大的后启动的先保留因为可能即将就绪。副本生命周期与故障恢复Replica Manager 通过 replica_managers.py 中的launch_cluster和terminate_cluster管理每个副本对应的独立 SkyPilot 集群并为每个副本注入环境变量SKYPILOT_SERVE_REPLICA_ID值取自 constants.py。副本状态机每个副本在数据库中维护一个ReplicaStatusserve_state.py非终态PENDING排队等待启动→PROVISIONINGVM 创建中→STARTING依赖安装/服务启动中→READY就绪探测通过→NOT_READY曾就绪但探测失败→SHUTTING_DOWN下线中终态失败FAILED用户 run/setup 失败、FAILED_INITIAL_DELAY超过初始延迟仍不健康、FAILED_PROBING健康检查失败、FAILED_PROVISION启动失败、FAILED_CLEANUP下线失败、PREEMPTEDSpot 被抢占/Kubernetes Pod 被驱逐。服务的整体状态则汇总为ServiceStatus如CONTROLLER_INIT、READY、FAILED、SHUTTING_DOWN等serve_state.py。不可恢复故障的熔断Autoscaler 在generate_scaling_decisions中会先检查最新版本是否有不可恢复故障unrecoverable_failure如果最新版本从未就绪、且副本进入终态失败如用户代码 bug 导致应用在就绪前崩溃则立即停止一切扩缩决策避免无限终止-重启循环浪费资源autoscalers.py。判断逻辑见 replica_managers.py只要服务曾经就绪过first_ready_time 0就认为用户代码无 bug失败可自动恢复。优雅下线与排空缩容/更新下线副本时terminate_cluster支持replica_drain_delay_seconds默认 120 秒见 replica_managers.py即先让副本进入排空状态、处理完在途请求再真正执行sky down。sky down失败会触发最多 3 次重试并标记FAILED_CLEANUP提示可能存在资源泄漏。命令行实战一键部署与运维安装 SkyPilot 后所有 Sky Serve 操作都通过sky serve子命令完成。启动服务# 部署一个名为 vllm 的服务 sky serve up -n vllm examples/serve/vllm.yaml启动后Controller 会自动在云端创建默认资源配置cpus: 4, memory: 8见 constants.py并在30001-30020端口范围内为负载均衡器分配端口constants.py。部署成功后控制台会打印服务 Endpoint 地址。默认的 Controller 自动停止策略为idle_minutes: 10, down: falseconstants.py可通过~/.sky/config.yaml中的serve.controller.autostop覆盖。查看状态与测试# 查看服务与副本状态 sky serve status vllm # 直接打印服务 Endpoint sky serve status --endpoint vllm # 用 curl 直接向 Endpoint 发请求验证 curl -L http://endpoint/v1/modelssky serve status会展示服务的ServiceStatus、每个副本的ReplicaStatus带颜色区分以及自动伸缩策略摘要Fixed 2 replicas、Autoscaling from 1 to 4 replicas (target QPS per replica: 2.0)等文本由autoscaling_policy_str()生成见 service_spec.py。状态输出效果可参考 docs/source/images/sky-serve-status-vllm.png 与 docs/source/images/sky-serve-status-vicuna-ready.png。查看日志# 服务端日志Controller 与负载均衡器 sky serve logs vllm --controller sky serve logs vllm --load-balancer # 按副本查看日志 sky serve logs vllm --replica 1更新与下线# 用新 YAML 滚动更新服务自动执行新一轮副本部署与流量切换 sky serve update vllm examples/serve/vllm.yaml # 下线服务并回收全部副本集群 sky serve down vllm更新采用版本化机制每次更新产生一个新version数据库version_specs表按(service_name, version)保存各版本规格serve_state.py。滚动更新期间新旧版本副本并存Autoscaler 依据active_versions协调下线节奏autoscalers.py。扩展阅读在仓库中继续深挖服务规范与全部配置字段sky/serve/service_spec.py负载均衡策略注册表与三种策略实现sky/serve/load_balancing_policies.py四种 Autoscaler 与滞回机制sky/serve/autoscalers.py副本状态机与故障恢复sky/serve/replica_managers.py、sky/serve/serve_state.py默认参数超时、端口、决策间隔sky/serve/constants.py更多可直接运行的示例vLLM 推理 examples/serve/vllm.yaml、Stable Diffusion examples/serve/stable_diffusion_service.yaml、多区域多副本的 Spot 策略示例 examples/serve/spot_policy从架构上看Sky Serve 把多云多副本推理服务的运维抽象成了三层负载均衡器只负责流量分发与请求时间戳上报Autoscaler 只负责根据指标产出扩缩容决策Replica Manager 只负责把决策落实为一个个真实的 SkyPilot 集群生命周期。理解这条职责链就能在遇到流量不均、伸缩迟缓或副本反复失败时快速定位问题出在哪个组件。【免费下载链接】skypilotThe AI Compute Platform for frontier teams. SkyPilot turns fragmented AI compute into one AI supercomputer, so frontier AI teams build custom intelligence faster.项目地址: https://gitcode.com/GitHub_Trending/sk/skypilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进