作者:车漾 徐之浩
在云原生技术飞速发展的过程中,我们看到容器和 Kubernetes (K8s) 已经成为云原生基础设施的核心支柱。
首先,容器技术实现了应用与运行环境的解耦,使得应用能够更加灵活地跨不同的环境进行部署和运行。而 Kubernetes 则通过集群资源管理、容器编排与任务调度功能,成为管理容器化应用的平台。
在此基础上,最早是从可水平扩展的无状态应用程序(如Web应用、移动后端应用)开始;然后是NoSQL数据库、关系数据库、TensorFlow、PyTorch、Spark、Flink等大数据和典型机器学习的AI计算任务。都能够在Kubernetes容器集群上大规模运行。
三方研究机构的预测,显示出同样的趋势。The Data on Kubernetes Community2022调查报告,90%的受访者认为Kubernetes已经可以很好支持有状态应用,其中70%的受访者已经将其运行在生产环境。DC的研究则预测,到2025年,接近50%的企业内部的数据密集型或性能密集型计算工作负载都将迁移到基于云的架构上,而基于云的架构正是典型的Cloud Native云原生架构。
在人工智能商业化的时代,模型推理比训练会被更加广泛地使用,因为它为人们提供有价值的服务。
可以预见,模型推理将成为未来的主要战场。这一点已经从现实中得到了印证——微软已经在 Azure 的60多个数据中心部署了数十万台 GPU,用于支持 ChatGPT的推理服务。
然而,大模型推理面临着巨大的挑战,主要集中在规模化部署的情况下,平衡成本和性能。其中,成本是最为关键的因素。随着大模型规模的不断扩大,其所需的计算资源也在不断增加。而由于 GPU 资源的稀缺性和高昂的价格,每次模型推理的成本也水涨船高。而最终用户只愿意为价值买单,而不是为推理的高成本买单。因此,降低每次推理的成本成为基础设施团队的首要任务。
由于GPU的稀缺性,多数人在大语言模型推理时往往需要为外部服务峰值预留固定数量的 GPU 实例。这样的做法能够保证服务的可靠性,但也带来了明显的资源浪费问题。在线推理场景下,流量的波峰波谷特征非常明显,例如聊天机器人在中午和夜间的流量较低,这导致了大量 GPU 资源的闲置。而 GPU 与传统 CPU 最大的区别在于其弹性伸缩的确定性不足,资源不会轻易释放,进一步加剧了浪费。
然而,我们从今天上午月之暗面的分享中得到了启发——如果能在低流量时解放 GPU 资源,进行一些模型训练和离线推理,就能有效提高资源的利用率。这种方法被称为“反向弹性伸缩”。因此,今天我们讨论的不是计算节点的传统弹性伸缩,而是在固定节点的情况下,通过工作负载的弹性伸缩和资源抢占来最大化资源利用率。
在 Kubernetes 中,提供了 HPA(Horizontal Pod Autoscaler)和 CronHPA两种机制来按需扩展实例数量,从而减少资源浪费:
●HPA 根据应用的实时负载调整实例数量:当负载增加时扩容,负载减少时缩容。
●CronHPA 是基于时间的 HPA,在固定时间点执行实例扩缩容。
但是,传统 HPA 存在一个问题——它根据实时负载扩容,通常在负载已经升高时才会触发扩容,导致业务因为高负载延迟而无法及时响应。这种现象被称为“弹性滞后”。而 CronHPA虽然能够按时间定时扩缩容,但它要求业务有非常明确的周期性,并且需要手动调整策略,增加了运维成本。
与传统在线服务相比,大模型推理的最大区别在于从启动到就绪所需的时间更长。传统应用通常能在几秒内启动,而大语言模型的启动时间却往往分钟级甚至10分钟级,这为弹性伸缩的配置带来了极大的挑战。
传统的基于 GPU 利用率的弹性伸缩并不能准确反映大语言模型推理服务的真实使用情况。实际上,GPU 利用率达到 100% 并不一定意味着系统已经处于繁忙状态。相比之下,基于并发数或每秒处理请求数(QPS/RPS)更能直接反映推理服务的性能表现。
为了解决这一问题,Knative提供了基于请求的自动弹性功能。它可以根据应用的请求量自动括缩容,从而最大化资源的利用率。这种方式不仅能在高峰期应对大规模并发请求,还能在低峰期自动释放资源,避免浪费。
背后的原因是,请求数通常是平滑上升的过程,这种方式能够更自然地跟随请求量的变化,确保系统在需求变化时及时响应,同时有效节省资源。
在一些离线推理场景中,延时要求不高时,可以在没有流量时将 Pod 数量缩减至 0,并在请求到来时自动扩容。Knative的开源版本支持此功能,通过“模式切换”实现。两种模式:Proxy 模式代理所有请求通过 activator 组件,Serve 模式允许请求直接到达 Pod。无请求时,系统切换为 Proxy 模式,activator 接收请求并触发扩容,Pod 准备好后切换到 Serve 模式,从而提升资源利用率和响应效率。
在云上使用 Knative面临挑战,主要问题是
1.组件多、运维复杂
2.Knative尚未完全适配 Serverless 容器,仍需节点运维。
3.Pod 冷启动时间过长,导致缩容到 0 难以实际应用。
为解决这些问题,ACK在完全兼容社区版 Knative的前提下,
1.提供了组件托管服务,帮助用户减少资源消耗和运维成本。
2.对接了阿里云的Serverless容器弹性实例。
3.通过保留资源池,避免冷启动并保障服务质量。通过引入智能 AHPA,利用历史数据实现弹性伸缩策略自动化,优化资源利用效率并降低运维成本。
ACK Knative在原生 KPA 基础上引入保留资源池,通过阿里云 serverless 容器增强缩容到 0 的能力。适用于 ECS 与 ECI 混用场景,用 ECS 资源处理常态请求时,突发流量可利用 ECI 扩容,确保资源高效利用。对于完全使用 ECI 的场景,保留资源池可预热资源,初始请求由低配实例处理,后续扩容由默认实例接管,实现低成本与无冷启动延时的平衡。此灵活调度提高了资源利用率和服务稳定性。
AHPA 弹性预测的关键出发点是通过历史数据检测到的周期性行为进行“定时规划”,从而先知先觉,提前扩容。然而,由于任何规划都会存在疏漏,因此我们还为其增加了实时调整能力。
基于这个思路,AHPA 提供了两种弹性策略: AHPA 提供两种弹性策略:
●主动预测,使用历史数据和达摩院的 RobustPeriod算法预测实例需求,适用于周期性流量
●被动预测,基于实时数据动态调整实例数,应对突发流量。
AHPA 还引入降级保护:支持配置多个时间区间范围最大、最小实例。提升了资源利用率和服务质量。
HPA扩容机制基于实时负载,只有当系统负载已经较高时才会触发扩容。这种滞后性意味着在新的实例启动之前,推理服务可能已经因为高负载而无法正常工作。如图所示,蓝色线条显示 HPA 触发扩容的时刻,而新实例的准备时间往往滞后于流量洪峰的到来。如果新实例不能在秒级内就绪,服务质量将受到影响。
AHPA通过提前预测解决这一问题,除了监控常见指标外,还考虑了应用 Pod 的冷启动时间。AHPA 将扩容触发时间左移,在流量峰值前提前扩容,确保 Pod 准备就绪,保障推理服务的稳定性与响应速度,特别适用于启动时间长的推理服务。
AHPA 提供丰富的数据指标支持,集成 Prometheus、Metrics Server、阿里云 SLS 等监控平台,覆盖资源和业务指标,还支持自定义监控。AHPA 复杂周期识别率达 95%,结合主动预测、被动预测和降级保护,确保精准弹性调整。
此外,AHPA 提供开箱即用的 Prometheus 可观测大盘,便于实时查看 Pod 预测趋势。
对于大模型在线推理往往具有潮汐式流量特点,AHPA 展现出非常友好的特性。,但最令人担忧的就是大量被动预测导致冷启动的情况,此时控制启动时间在秒级内至关重要。
对于大模型推理服务的场景来说,弹性扩容并不是一个瞬间可以完成的动作,而是一个从开始扩容资源到推理服务就绪的过程。如何能够加速这个就绪的过程呢?在这里我们会利用到Fluid这个项目。Fluid是一个面向Kubernetes环境数据密集型应用的数据编排和加速框架。它目前也是CNCF基金会下的一个官方沙箱项目。Fluid的核心思路是通过部署一套分布式缓存,来加速同在Kubernetes集群中运行的一系列I/O密集型的任务。
Fluid基于分布式缓存能力,实现了数据弹性与调度、数据访问接入与适配、数据流任务编排等核心功能,这些功能主要目的都是帮助用户以更加高效、简单、灵活的方式使用多种不同的分布式缓存引擎。
这里我们会聚焦在Fluid项目对于模型推理服务冷启动速度的优化上。首先从测试结果上来看,使用Fluid可以时vLLM + Qwen模型推理服务的启动耗时分别缩短10.3和14.9倍。并且从更细粒度的数据上来看,模型推理服务冷启动时间很长的原因,主要来自于模型加载过程(上图橙色部分)。Fluid通过对模型加载过程的I/O进行优化,最终将两个模型推理服务的启动时间压缩到1分钟,甚至是半分钟以内。
Fluid加速模型加载过程主要做了两方面的I/O优化。一方面,多卡GPU节点I/O带宽资源是非常充裕的,AI应用没有充分利用这些带宽资源,导致模型加载过程非常缓慢。Fluid则会使用一个SDK发起多线程预读,最大化利用单个AI应用Pod的可用带宽,加速模型加载过程。
另一方面,应用能够获取的带宽也取决于模型存储系统能够提供多大的带宽。因为弹性扩容往往是同时扩容多个Pod,模型存储系统提供的带宽将被多个Pod均分,每一个Pod平均获得的带宽就更少。Fluid提供一个能够弹性伸缩的分布式缓存,来匹配这种带宽需求上的动态变化。
AI应用难以充分利用GPU节点上的I/O带宽资源,这里问题的核心来自于AI应用自身的文件访问模式。LLM模型参数通常以safetensors格式分发,而读取safetensors格式文件的过程是一个随机读过程。如左图所示,左图横轴为读取请求的序数,纵轴则为读取请求的offset值,相邻读取请求的offset值变化很大,整体呈现一个随机读的特征。
这种随机读的特征对于存储在本地SSD盘中模型文件影响不会很大,但容器化环境中,模型往往存储在远程存储系统中,随机读让这些文件系统客户端的I/O效率显著降低。经我们测试,机器节点的实际带宽利用率不到20%。Fluid解决方案将safetensors格式文件预读到对随机读友好的本地内存缓存中,由于预读过程是一个顺序读取的过程,能够充分利用节点上可用的带宽资源。另外,Fluid实现的预读是“旁路的”,当AI应用开始加载模型时,无需修改AI应用的加载代码,它的读取请求就会自动命中本地内存缓存。
对于这个优化,我们针对不同的场景,为用户提供了两种不同的使用方式。
1.是直接在应用Pod中注入一个Sidecar容器,由Sidecar容器使用FluidSDK发起这个预读过程。对于业务没有任何的侵入性,业务Pod可以无感地享受到预读带来的I/O优化效果。
2.则是为了支持一些更进阶的使用场景,例如根据用户指定的模型,动态地汰换GPU显存中的模型。对于这种场景,Fluid提供了Fluid SDK,业务代码只需要新增一个函数,就可以对待加载的模型启用预读。
使用优化一后,各个AI应用Pod能够以接近所在节点的最大带宽来加载LLM模型参数数据。但是当有多个这样的AI应用Pod同时弹性扩容的时候,他们对存储系统的带宽需求也就自然翻倍了。随着业务规模越来越大,扩的越来越多,这个带宽的需求就会不断的增加上去。远程存储系统往往没有办法满足这种巨大的、弹性的带宽需求。对于这个问题,Fluid提供一个随业务需求弹性扩缩容的分布式缓存系统,扩缩容策略同样支持主动扩缩容,或者是HPA、CronHPA、AHPA这样的自动扩缩容策略。用户不仅可以在业务洪峰时扩容分布式缓存以提供更大的存储系统侧供给带宽,也可以在不再需要这些带宽的时候缩容甚至是降级。
除了上文提到的性能方面的优化以外,Fluid同样希望让用户以最小的负担使用分布式缓存。DataFlow数据流就是一个能够简化AI应用更新发布流程的Fluid功能。Fluid定义了一个数据操作Operation的概念,多个数据操作可以按照一个链条的串联顺序按序执行,其中一些操作是Fluid自建提供的,例如与缓存系统相关的扩容(Scale Out)、缩容(Scale In)、缓存预热(Cache Warmup)等操作。另外一些操作则是完全由用户指定它的行为。这些步骤可以通过Fluid SDK的若干行代码就可以提交到集群中,Fluid将会自动控制这些操作的执行顺序, 不需要人工费时费力的去参与。
接下来我们通过一个Demo演示在模型推理服务场景下,Fluid的加速效果和使用方式。我们会使用vLLM作为推理框架,Qwen-7B作为推理框架需要去加载的LLM模型。
首先,创建两个Fluid的自定义资源(Custom Resource):Dataset和JindoRuntime。在Dataset中定义Qwen-7B模型的OSS存储路径;在JindoRuntime中定义分布式缓存系统Worker的副本数以及每个副本提供的缓存容量。
创建上述两个资源后,等待一段时间(约40s),Fluid将在Kubernetes集群中自动配置并部署分布式缓存系统,当看到Dataset的PHASE
字段变为“Bound”时,则说明JindoCache分布式缓存系统部署就绪。此时,Fluid会自动创建该缓存系统对应的PVC和PV,后续应用需要挂载PVC以访问缓存系统中的数据。
在实际创建应用Pod之前,可以先通过Fluid的DataLoad数据操作执行主动的缓存预热。例如,在上图的例子中,dataload.yaml
指定对名为llm-model
的Fluid Dataset进行预热,预热的范围是整个数据集中的全部数据,也就是我们马上将要读取的Qwen-7B模型参数文件。
等待一段时间,当看到model-dataload
资源的PHASE
状态变为“Complete”时,说明数据预热操作已完成。此时创建一个Knative Service自定义资源对象,该资源对象中,通过preload-files-sidecar.fluid.io/xxx
的若干个标签和注解,使用Sidecar方式为该模型推理服务启用Fluid的预读优化。模型推理服务所使用的镜像为vLLM开源社区提供的官方镜像。
创建Knative Service资源后,分别查询资源的访问域名以及Knative的网关信息并记录到SERVICE_HOSTNAME
和KOURIER_GATEWAY_IP
环境变量中。使用这两个环境变量,使用curl命令准备发起一条HTTP请求,请求格式遵OpenAI格式,向Qwen-7B发送“Hello,Qwen”的聊天内容,并记录该请求的最终返回时间。在真正发起该HTTP请求前,可以在右侧终端中看到,集群中此时不包含任何模型推理服务的Pod,即整个过程从0扩容。
发起HTTP请求,此时Knative接受到请求,弹性扩容出一个模型推理服务Pod,推理服务Pod冷启动时使用了Fluid的优化。最终该请求的返回延时为15.79s,返回内容符合预期(content=“Hello!How can I assist you today?”)。
使用Demo中的测试数据,我们发现,相比于直接读取OSS,使用Fluid方案可以使得模型加载耗时下降为原来的16分之一,首请求的延时也能够下降大约67%。
总结
针对模型推理的挑战,本文探讨了多种优化策略,特别是Knative的弹性扩展机制,结合Horizontal Pod Autoscaler (HPA) 和CronHPA实现灵活的资源管理。然而,传统弹性扩展存在“弹性滞后”的问题,难以应对突发流量。因此,AHPA(高级弹性预测)成为解决这一问题的关键,基于历史数据的主动预测能够提前扩容,确保服务稳定性。
此外,Fluid项目为加速大模型推理服务冷启动提供了重要支持。Fluid通过分布式缓存优化了模型加载的I/O操作,尤其针对AI应用的随机读特性进行了有效优化,使推理服务的启动耗时大幅缩短。结合Fluid的多种功能,如Sidecar容器预读和分布式缓存的弹性伸缩,推理服务能够更高效地应对大规模并发请求。
通过实际测试,Fluid在vLLM和Qwen模型推理中的应用显著减少了加载时间,并降低了端到端的响应延时。尤其是在资源有限的GPU节点上,Fluid通过优化I/O带宽,显著提高了模型推理的效率,为未来的AI推理服务提供了强有力的支撑。