基于指标的自动扩缩容#

AIBrix 自动扩缩容器包括各种基于指标的自动扩缩容组件,允许用户方便地选择合适的扩缩容器。这些选项包括基于 Knative 的 Kubernetes Pod 自动扩缩容器 (KPA)、原生 Kubernetes 横向 Pod 自动扩缩容器 (HPA) 和 AIBrix 为 LLM 服务量身定制的自定义高级 Pod 自动扩缩容器 (APA)。

在以下章节中,我们将演示用户如何在 AIBrix 中创建各种类型的自动扩缩容器。

支持的自动扩缩容机制#

  • HPA:与原生的 K8s HPA 相同。当用户在 AIBrix 中部署需要 HPA 的规范时,会使用原生 Kubernetes 自动扩缩容器 HPA。此设置根据 CPU 利用率扩展演示部署的副本。

  • KPA:来自 Knative。KPA 具有紧急模式,可以根据短期历史记录更快地扩容。可以实现更快的扩容。KPA 受 Knative 启发,维护两个时间窗口:一个较长的 稳定 窗口 和一个较短的 紧急 窗口。它根据紧急窗口的测量结果,通过快速扩容资源来应对流量的突然激增。与其他可能依赖 Prometheus 收集部署指标的解决方案不同,AIBrix 内部获取和维护指标,从而实现更快的响应时间。使用模拟的基于 vllm 的 Llama2-7b 部署的 KPA 扩缩容操作示例。

  • APA:类似于 HPA,但它具有波动参数,该参数作为触发扩容和缩容前的最小缓冲区,以防止振荡。

HPA 和 KPA 虽然被广泛使用,但它们并非专门为 LLM 服务设计和优化,而 LLM 服务具有独特的优化点。AIBrix 的自定义 APA (AIBrix Pod Autoscaler) 解决方案将逐步引入以下功能:

  • 根据 AI 运行时指标标准化选择适合 LLM 的扩缩容指标。

  • 主动扩缩容算法而非被动算法。(WIP)

  • 性能分析和 SLO 驱动的自动扩缩容解决方案。(测试阶段)

指标#

AiBrix 支持所有 vllm 指标。请参阅 https://docs.vllm.com.cn/en/stable/design/metrics.html

如何部署自动扩缩容策略#

只需应用 PodAutoscaler yaml 文件即可。您需要注意的一点是,部署名称和 PodAutoscaler 中 scaleTargetRef 的名称必须相同。AiBrix PodAutoscaler 就是通过这种方式引用正确的部署的。

所有示例文件都可以在以下目录中找到。

https://github.com/vllm-project/aibrix/tree/main/samples/autoscaling

HPA yaml 配置示例#

apiVersion: autoscaling.aibrix.ai/v1alpha1
kind: PodAutoscaler
metadata:
  name: deepseek-r1-distill-llama-8b-hpa
  namespace: default
  labels:
    app.kubernetes.io/name: aibrix
    app.kubernetes.io/managed-by: kustomize
spec:
  scalingStrategy: HPA
  minReplicas: 1
  maxReplicas: 10
  metricsSources:
    - metricSourceType: pod
      protocolType: http
      port: '8000'
      path: /metrics
      targetMetric: gpu_cache_usage_perc
      targetValue: '50'
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: deepseek-r1-distill-llama-8b

KPA yaml 配置示例#

apiVersion: autoscaling.aibrix.ai/v1alpha1
kind: PodAutoscaler
metadata:
  name: deepseek-r1-distill-llama-8b-kpa
  namespace: default
  labels:
    app.kubernetes.io/name: aibrix
    app.kubernetes.io/managed-by: kustomize
  annotations:
    kpa.autoscaling.aibrix.ai/scale-down-delay: 3m
spec:
  scalingStrategy: KPA
  minReplicas: 1
  maxReplicas: 8
  metricsSources:
    - metricSourceType: pod
      protocolType: http
      port: '8000'
      path: metrics
      targetMetric: gpu_cache_usage_perc
      targetValue: '0.5'
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: deepseek-r1-distill-llama-8b

APA yaml 配置示例#

apiVersion: autoscaling.aibrix.ai/v1alpha1
kind: PodAutoscaler
metadata:
  name: deepseek-r1-distill-llama-8b-apa
  namespace: default
  labels:
    app.kubernetes.io/name: aibrix
    app.kubernetes.io/managed-by: kustomize
  annotations:
    autoscaling.aibrix.ai/up-fluctuation-tolerance: '0.1'
    autoscaling.aibrix.ai/down-fluctuation-tolerance: '0.2'
    apa.autoscaling.aibrix.ai/window: 30s
spec:
  scalingStrategy: APA
  minReplicas: 1
  maxReplicas: 8
  metricsSources:
    - metricSourceType: pod
      protocolType: http
      port: '8000'
      path: metrics
      targetMetric: gpu_cache_usage_perc
      targetValue: '0.5'
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: deepseek-r1-distill-llama-8b

StormService 角色级自动扩缩容#

对于池化模式下的 StormService (replicas=1),不同的角色(例如,预填充和解码)可以独立进行自动扩缩容。这允许精细控制,每个角色根据其特定指标进行扩缩容。

使用 subTargetSelector 字段来定位 StormService 中的特定角色。此外,将注释 autoscaling.aibrix.ai/storm-service-mode: “pool” 添加到 PodAutoscaler 对象。这有助于 AIBrix 自动扩缩容器更好地区分 replicas=1 的场景。

主要功能

  • 每个角色都有自己的 PodAutoscaler,具有独立的指标和扩缩容策略

  • 与池化模式下的 StormService (replicas=1) 配合使用

  • 每个角色支持不同的扩缩容策略(HPA、KPA、APA)

  • 允许每个角色具有不同的最小/最大副本数和扩缩容行为

完整示例

# Example: Independent autoscaling for prefill and decode roles in StormService
#
# This demonstrates how to scale different roles independently based on their
# specific metrics in StormService pooled mode (replicas=1).

---
# PodAutoscaler for prefill role
apiVersion: autoscaling.aibrix.ai/v1alpha1
kind: PodAutoscaler
metadata:
  name: ss-pool-prefill
  namespace: default
  annotations:
    autoscaling.aibrix.ai/storm-service-mode: "pool"
spec:
  scaleTargetRef:
    apiVersion: orchestration.aibrix.ai/v1alpha1
    kind: StormService
    name: ss-pool

  # Select the prefill role within the StormService
  subTargetSelector:
    roleName: prefill

  minReplicas: 2
  maxReplicas: 20
  scalingStrategy: APA

  metricsSources:
    - metricSourceType: pod
      protocolType: http
      port: "8000"
      path: /metrics
      targetMetric: "prefill_queue_length"
      targetValue: "10"

---
# PodAutoscaler for decode role
apiVersion: autoscaling.aibrix.ai/v1alpha1
kind: PodAutoscaler
metadata:
  name: ss-pool-decode
  namespace: default
  annotations:
    autoscaling.aibrix.ai/storm-service-mode: "pool"
spec:
  scaleTargetRef:
    apiVersion: orchestration.aibrix.ai/v1alpha1
    kind: StormService
    name: ss-pool

  # Select the decode role within the StormService
  subTargetSelector:
    roleName: decode

  minReplicas: 3
  maxReplicas: 30
  scalingStrategy: APA

  metricsSources:
    - metricSourceType: pod
      protocolType: http
      port: "8000"
      path: /metrics
      targetMetric: "decode_batch_utilization"
      targetValue: "70"

  # Different scaling behavior for decode
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 600  # More conservative scale-down

---
# The StormService being autoscaled (pooled mode)
apiVersion: orchestration.aibrix.ai/v1alpha1
kind: StormService
metadata:
  name: ss-pool
  namespace: default
spec:
  updateStrategy:
    type: InPlaceUpdate
    maxSurge: 2
    maxUnavailable: 1
  replicas: 1  # Pooled mode
  stateful: true
  selector:
    matchLabels:
      app: llm-xpyd
  template:
    metadata:
      labels:
        app: llm-xpyd
    spec:
      roles:
        - name: prefill
          replicas: 5  # Will be managed by PodAutoscaler
          stateful: true
          template:
            spec:
              containers:
                - name: prefill
                  image: vllm/vllm-openai:latest
                  ports:
                    - containerPort: 8000
                      name: metrics
                  # ... other config

        - name: decode
          replicas: 5  # Will be managed by PodAutoscaler
          stateful: true
          template:
            spec:
              containers:
                - name: decode
                  image: vllm/vllm-openai:latest
                  ports:
                    - containerPort: 8000
                      name: metrics
                  # ... other config

何时使用

  • 池化模式:StormService replicas=1,其中角色需要独立扩缩容

  • 不同的工作负载模式:预填充和解码具有不同的资源需求和流量模式

  • 独立指标:每个角色都有自己的指标(例如,队列长度、批处理利用率)

基于多指标的自动扩缩容#

AIBrix 支持多指标自动扩缩容,允许用户在单个 PodAutoscaler 资源中定义多个扩缩容指标。这对于 LLM 服务工作负载特别有用,因为单个指标(例如 GPU 缓存使用率)可能无法完全捕捉系统压力——将其与基于队列的指标(例如等待请求的数量)结合使用,可以实现更健壮和响应更快的扩缩容决策。

工作原理#

  • 当在 spec.metricsSources 下指定多个指标时,自动扩缩容器会独立评估所有指标。

  • 最终所需的副本数由要求最高副本数的指标决定(即“最大”策略)。

配置示例#

以下 PodAutoscaler 同时使用两个指标和 APA 策略

apiVersion: autoscaling.aibrix.ai/v1alpha1
kind: PodAutoscaler
metadata:
  name: deepseek-r1-mock-llama2-7b-multi-metrics
  namespace: default
  labels:
    app.kubernetes.io/name: aibrix
    app.kubernetes.io/managed-by: kustomize
  annotations:
    autoscaling.aibrix.ai/up-fluctuation-tolerance: '0.1'
    autoscaling.aibrix.ai/down-fluctuation-tolerance: '0.2'
    apa.autoscaling.aibrix.ai/window: 30s
spec:
  scalingStrategy: APA
  minReplicas: 1
  maxReplicas: 3
  metricsSources:
    - metricSourceType: pod
      protocolType: http
      port: '8000'
      path: metrics
      targetMetric: gpu_cache_usage_perc
      targetValue: '0.5'
    - metricSourceType: pod
      protocolType: http
      port: '8000'
      path: metrics
      targetMetric: num_requests_waiting
      targetValue: '100'
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: mock-llama2-7b

检查自动扩缩容日志#

Pod 自动扩缩容器日志#

Pod 自动扩缩容器是 aibrix 控制器管理器的一部分,负责从每个 pod 收集指标。您可以通过以下方式查看其日志。

kubectl logs <aibrix-controller-manager-podname> -n aibrix-system -f

预期日志输出。您可以看到当前指标是 gpu_cache_usage_perc。您可以检查每个 pod 的当前指标值。

AiBrix controller manager output

自定义资源状态#

要描述 PodAutoscaler 自定义资源,您可以运行

kubectl describe podautoscaler <podautoscaler-name>

示例输出在此处,您可以查看扩缩容条件和事件以获取更多详细信息。

PodAutoscaler describe

不同自动扩缩容器的初步实验#

这里我们展示初步实验结果,以展示不同的自动扩缩容机制和自动扩缩容器的配置如何影响性能(延迟)和成本(计算成本)。在 AiBrix 中,用户可以通过简单地应用 K8s yaml 轻松部署不同的自动扩缩容器。

  • 设置
    • 模型:Deepseek 7B 聊天机器人模型

    • GPU 类型:V100

    • 最大 GPU 数量:8

  • 目标指标和值
    • 目标指标:gpu_kv_cache_utilization

    • 目标值:50%

  • 工作负载
    • 整体 RPS 趋势从低 RPS 开始,然后相对较快地上升,直到 T=500,以评估不同的自动扩缩容器和配置对快速负载增加的反应。之后,它迅速下降到低 RPS,以评估缩容行为,然后再次缓慢上升。
      • 平均 RPS 趋势:1 RPS -> 4 RPS -> 8 RPS -> 10 RPS -> 2 RPS -> 6 RPS

    • RPS 可以在第二个子图中找到。

  • 性能
    • HPA 具有最高的延迟,因为它的反应缓慢。KPA 在紧急模式下反应最快。APA 以较小的延迟窗口运行以节省成本。它确实节省了成本,但当它在 T=700 到 T=1000 期间过于激进地缩容时,最终导致比 KPA 更高的延迟。

  • 成本
    • 第四张图显示了随时间变化的相对累积计算成本。累积成本通过时间乘以单位成本(在本例中为 1)计算。实际计算成本可以通过乘以实际单位时间成本来计算。

    • HPA 由于缩容延迟窗口较长而成本最高。

    • APA 响应最快,节省的成本最多。您可以看到它比其他两个自动扩缩容器波动更大。

    • 请注意,缩容窗口不是每个自动扩缩容机制固有的功能。它是一个可配置的变量。我们使用 HPA 的默认值(300s)。

  • 结论
    • 没有一个自动扩缩容器在所有指标(延迟、成本)上都优于其他自动扩缩容器。此外,结果可能取决于工作负载。基础设施应提供简单的方法来配置他们想要的任何自动扩缩容机制,并且应该易于配置,因为不同的用户有不同的偏好。例如,一个人可能更喜欢成本而不是性能,反之亦然。

result