Knative和AI结合提供了快速部署、高弹性和低成本的技术优势,适用于需要频繁调整计算资源的AI应用场景,例如模型推理等。您可以通过Knative Pod部署AI模型推理任务,配置自动扩缩容、灵活分配GPU资源等功能,提高AI推理服务能力和GPU资源利用率。
加速模型部署
为了保证Knative Serving部署的AI模型推理服务实现快速的伸缩能力,应避免将AI模型打包到容器镜像中。当AI模型和容器镜像打包在一起时,容器的大小会显著地增大,从而减缓容器的部署速度。此外,当AI模型被打包在容器内时,AI模型的版本将与容器镜像版本绑定,增加了版本控制的复杂性。
为避免上述问题,推荐您将AI模型的数据加载到对象存储OSS、文件存储NAS等外部介质中,并通过PVC挂载到Knative服务Pod中。同时,可使用分布式数据集编排和加速引擎Fluid来加速对AI模型的读取和加载过程(参见JindoFS加速OSS文件访问、EFC加速NAS文件访问等相关文档),实现大模型的秒级加载。
前提条件
步骤一:定义数据集
当您将AI模型存放在对象存储OSS时,可以使用Dataset来声明OSS上的数据集,并使用JindoRuntime执行缓存任务。
步骤二:挂载PVC实现加速效果
声明Dataset和JindoRuntime后,系统会自动创建同名PVC,将PVC挂载到Knative服务中即可实现加速效果。
步骤三:通过镜像缓存实现秒级加载
除AI模型本身之外,也需要考虑容器镜像大小对Knative服务的影响。运行AI模型的服务容器往往需要打包CUDA、pytorch-gpu等一系列依赖,导致其容器镜像大小显著增加。当使用ECI Pod部署Knative AI模型推理服务时,建议使用ImageCache来加速镜像的拉取过程,ImageCache能够为ECI Pod提供镜像缓存功能,通过提前缓存镜像来显著加速镜像拉取时间、实现秒级镜像拉取,参见使用ImageCache加速创建ECI Pod。
apiVersion: eci.alibabacloud.com/v1
kind: ImageCache
metadata:
name: imagecache-ai-model
annotations:
k8s.aliyun.com/eci-image-cache: "true" # 开启镜像缓存复用。
spec:
images:
- <YOUR-IMAGE>
imageCacheSize:
25 # 镜像缓存大小,单位GiB。
retentionDays:
7 # 镜像缓存保留时间。
优雅关闭容器
为了确保正在进行的请求不会突然终止,容器应在收到SIGTERM信号时启动正常关闭。
收到SIGTERM信号后,如果应用程序使用HTTP探测,则设置容器为非就绪状态,防止将新的请求转发给正在关闭的容器。
在关闭过程中,Knative的queue-proxy可能仍在将请求转发到容器。建议将
timeoutSeconds
参数应该设置为最长预期处理请求响应时间的1.2倍左右,以确保所有请求可以在容器终止之前完成。例如,如果最长的请求响应时间需要10秒,建议将timeoutSeconds
参数设置为12秒。apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go namespace: default spec: template: spec: timeoutSeconds: 12
并发参数配置
通过正确配置并发参数,您可以显著提升Knative服务的性能和响应速度。这些设置可以帮助您的应用程序更有效地处理高并发请求负载,从而提高整体的服务质量和用户体验。
并发硬限制:硬限制是强制上限。如果并发达到硬限制,多余的请求将被缓冲,并且必须等待,直到有足够的可用资源来执行请求。
并发软限制:软限制是有针对性的限制,而不是严格的约束。在类似请求突然爆发的情况下,可能会超过该值。
目标使用率:相较于直接修改
target
,调整目标使用率autoscaling.knative.dev/target-utilization-percentage
提供了更直观的并发级别管理方式。将此配置接近 100% 可以实现最高效的并发处理。
更多详细说明及实例,请参见并发数配置介绍。
自动弹性扩缩容
在对自动弹性进行调整之前,首先需定义优化目标,例如减少延迟、最大限度地降低成本或适应尖峰流量模式。然后测量Pod在预期场景下启动所需的时间。例如,部署单个Pod可能与同时部署多个Pod具有不同的方差和平均启动时间。这些指标为自动弹性配置提供了基准。
更多参数信息及配置说明,请参见基于流量请求数实现服务自动扩缩容。
扩缩容模式
自动弹性有两种模式,稳定模式(Stable Mode)和恐慌模式(Panic Mode),每种模式都有单独的窗口。稳定模式用于一般操作,而恐慌模式默认情况下具有更短的窗口,用于在流量突发时快速扩容Pod。
稳定模式窗口
通常为了保持稳定的扩缩容行为,稳定窗口应该比平均Pod启动时间长,推荐设置为平均时间的2倍。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/window: "40s"
恐慌模式窗口
恐慌窗口是稳定窗口的百分比。其主要功能是管理突然的、意外的流量高峰。
此配置容易导致过度扩容,尤其当Pod启动时间较长时。请谨慎配置。
如果稳定窗口设置为30秒,恐慌窗口配置为10%,则系统将使用3秒的数据来判断是否进入恐慌缩放模式。如果Pod通常需要30秒才能启动,则系统可能会在新Pod仍在上线时继续扩容,从而可能导致过度扩容Pod。
在调整其他参数并确保缩放行为稳定之前,避免对恐慌窗口进行微调,尤其是当考虑到恐慌窗口的值短于或等同于Pod启动时间的情形。若稳定窗口为平均Pod启动时间的两倍,可以考虑将恐慌窗口值设定为50%,以此作为平衡正常和高峰流量模式的起点。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/panic-window-percentage: "20.0"
恐慌模式阈值是传入流量与服务容量的比率。根据流量的尖峰和可接受的延迟水平来调整此值。初始值为200%或更高,直到缩放行为稳定。服务运行一段时间之后,可以考虑进一步调整。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/panic-threshold-percentage: "150.0"
弹性速率
为了更好地响应流量模式,可以通过调整扩容和缩容速率来控制系统的弹性。默认配置通常能够满足大部分需求,但在特定场景下可能需要进行相应的调整。在调整速率之前需要观察当前情况,并优先在测试环境中进行更改和验证,以评估其影响。如果遇到扩缩容问题,请检查与扩容和缩容速率相关的参数,如稳定窗口和恐慌窗口等。
扩容速率
除非遇到特定问题,否则扩容速率通常不需要修改。例如,如果同时对多个Pod进行扩容,可能由于需等待资源的分配,导致启动时间延长,则需要调整扩容速率。如果观察到频繁扩缩,可能还需要考虑调整其他相关参数,如稳定窗口或者恐慌窗口大小,以优化伸缩行为。
apiVersion: v1
kind: ConfigMap
metadata:
name: config-autoscaler
namespace: knative-serving
data:
max-scale-up-rate: "500.0"
缩容速率
缩容速率最初应设置为平均Pod启动时间或更长。默认值通常足以满足大多数使用情况,但如果重点在于优化成本,可以考虑调高速率,以便在流量高峰后更快地缩容。
缩容率是一个乘数,例如,值N/2将允许系统在弹性周期结束时将Pod数量缩减至当前数量的一半。对于Pod数量较少的服务,较低的缩容率有助于保持Pod数量更加平滑,避免频繁地伸缩造成的波动,从而提高系统稳定性。
apiVersion: v1
kind: ConfigMap
metadata:
name: config-autoscaler
namespace: knative-serving
data:
max-scale-down-rate: "4.0"
延迟缩容
可以通过指定延迟缩容的时间窗口,避免新请求进入时频繁扩缩容,导致响应延迟的问题。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld-go
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/scale-down-delay: "2m" // 表示延迟 2 分钟缩容
扩缩容边界
这些参数与业务的规模和可用资源高度相关。
下限
autoscaling.knative.dev/min-scale
控制每个修订版应具有的最小副本数。Knative将保持不少于此数量的副本。对于那些使用率不高但需要保持始终可用的服务,将该值设置为1可以确保至少有一个副本始终运行。对于可能会有大量突发流量的服务,应将此值设定高于1以提高应对能力。如果希望服务能够在无流量时缩减到零副本,可将该值设置为0。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/min-scale: "0"
上限
autoscaling.knative.dev/max-scale
不应超过可用资源。使用此参数主要限制最大资源成本。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/max-scale: "3"
初始扩容数
配置初始规模,建议配置为现有Pod数量的1.2倍左右,以便新版本可以充分处理现有流量。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld-go
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/initial-scale: "3"
共享GPU调度
结合ACK共享GPU调度能力,Knative模型服务可以充分利用cGPU显存隔离能力,高效利用GPU设备资源。
在Knative使用共享GPU只需要在Knative Service中limits
设置aliyun.com/gpu-mem
参数即可,示例如下。
探针配置
您可以通过配置存活探针(Liveness Probe)和就绪探针(Readiness Probe)监测Knative服务的健康和可用性。相较于 Kubernetes 的探针策略,Knative 采用更频繁的积极探测,以最大限度减少冷启动时间,加速 Pod 启动到运行的过程。
Liveness Probe:存活探针用于监视容器的健康状况。如果容器处于失败状态或在容器运行中服务未成功启动,存活探针将重新启动容器。
Readiness Probe:配置就绪探针可以有效管理应用的自动扩缩容过程,确保只有准备好的实例可以接收流量,从而提升系统的可靠性和响应效率。
在加载所有组件并且容器完全准备好之前,TCP探针不会启动监听端口。
在端点能够处理请求之前,HTTP探测不应将服务标记为就绪。
调整探测间隔periodSeconds时,请保持较短的间隔。理想情况下,该时间应小于默认值10秒。
更多详细说明及最佳实践,请参见在Knative中配置端口探测。
按需自动缩容至零以节约资源
Knative的突出功能之一是能够在服务不使用时将Pod缩容至零。
对于需要管理多个模型的用户,推荐为每个独立的模型创建单独的Knative服务,以避免在一个服务内部集成复杂的业务逻辑。
借助Knative的缩容到零的功能,可以做到长时间未被访问的模型不会产生资源成本。
当客户端第一次访问模型服务时,Knative能够实现从零状态开始的自动扩容。
更多详细说明及最佳实践,请参见配置保留实例。
基于多版本设置合理的灰度节奏
Knative优势之一是可以确保不间断的服务可用性,特别是在推出新版本时。当部署新代码或对服务进行更改时Knative会保持旧版本运行,直到新版本准备就绪。
可以通过流量百分比阈值进行配置。流量百分比是一个关键参数,它决定Knative何时应将流量从旧版本切换到新版本。该百分比可以低至10%,也可以高达100%,取决于具体需求。对于不需要旧服务的非生产环境,可以将流量百分比设置为100%。当新版本准备就绪时,会立即关闭旧版本。
在Pod可用性有限的情况下进行大规模操作时,需要控制旧版本的缩容速度。如果某个服务在500个Pod上运行,而只有300个额外的Pod可用,那么设置过大的流量百分比可能会导致服务部分不可用。
更多详细说明及最佳实践,请参见基于流量灰度发布服务。
ECS和ECI资源混用
如果希望常态情况下使用ECS资源,突发流量时使用ECI,那么可以结合ResourcePolicy来实现。在常态下通过ECS资源承载流量,而在遇到突增的流量时,额外扩容的资源会使用ECI进行承载。
在扩容过程中,Knative Pod会优先利用ECS资源进行扩展。当Pod数量超过预设的最大值,或ECS资源不足时,则会转而使用ECI来创建新的Pod。
缩容时,会根据调度节点的逆序,优先缩容在ECI上的Pod。
更多详细说明及最佳实践,请参见在Knative中同时使用ECS和ECI资源。