异构 GPU 推理(实验性)

异构GPU推理(实验性)#

异构GPU推理是一项允许用户使用不同类型GPU部署相同模型的功能。此功能解决了大型语言模型(LLM)推理相关的两个主要挑战:(1) 随着大规模模型推理需求的增加,确保GPU一致性已成为一个挑战,特别是在容量限制导致相同GPU类型通常不可用的区域。(2) 用户可能寻求整合成本较低、性能较低的GPU,以降低整体开销。

设计概述#

异构GPU推理功能包含三个主要组件:(1) LLM请求监控,(2) 异构GPU优化器,(3) 请求路由。下图展示了整体架构。首先,LLM请求监控组件负责监控过去的推理请求及其请求模式。其次,异构GPU优化器组件负责选择最佳GPU类型和相应的GPU数量。第三,请求路由组件负责将请求路由到最佳GPU。

heterogeneous-gpu-diagram

示例#

准备:启用相关组件,包括网关处的请求跟踪。

# delete related components with experimental features disabled by default.
kubectl delete -k config/experimentals/gpu-optimizer
# redeploy related components with experimental features enabled.
kubectl apply -k config/experimentals/gpu-optimizer

或者,您可以通过编辑网关插件部署来启用该功能,使用 kubectl edit deployment aibrix-gateway-plugins -n aibrix-system 并附加环境变量。

# spec:
#   template:
#     spec:
#       containers:
#         - name: gateway-plugin
#           env:
            - name: AIBRIX_GPU_OPTIMIZER_TRACING_FLAG
              value: "true"

步骤1:部署异构部署。

每种GPU类型应部署一个部署和相应的PodAutoscaler。请参阅异构配置示例,了解由两种GPU类型组成的异构配置示例。以下代码使用L20和V100 GPU部署异构部署。

kubectl apply -f samples/heterogeneous

部署后,您将看到一个推理服务,其中有两个Pod在模拟的L20和A10 GPU上运行。

kubectl get svc
NAME                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
deepseek-coder-7b   NodePort    10.102.95.136   <none>        8000:30081/TCP   2s
kubernetes          ClusterIP   10.96.0.1       <none>        443/TCP          54d

传入请求通过网关路由,并根据请求模式导向最佳Pod

kubectl get pods
NAME                                       READY   STATUS    RESTARTS   AGE
deepseek-coder-7b-v100-96667667c-6gjql     2/2     Running   0          33s
deepseek-coder-7b-l20-96667667c-7zj7k      2/2     Running   0          33s

步骤2:安装aibrix Python模块。

pip3 install aibrix

GPU优化器在后台持续运行,根据工作负载模式动态调整每个模型的GPU分配。请注意,GPU优化器需要针对每种GPU类型在每个特定LLM模型上的离线推理性能基准数据。

如果使用本地异构部署,您可以在 python/aibrix/aibrix/gpu_optimizer/optimizer/profiling/result/ 下找到准备好的基准数据,并跳过步骤3。有关部署本地异构部署的详细信息,请参阅 开发

步骤3:基准测试模型。

对于每种GPU类型,运行 aibrix_benchmark。有关更多选项,请参阅 benchmark.sh

kubectl port-forward [pod_name] 8010:8000 1>/dev/null 2>&1 &
# Wait for port-forward taking effect.
aibrix_benchmark -m deepseek-coder-7b -o [path_to_benchmark_output]

步骤4:决定SLO并生成配置文件。

运行 aibrix_gen_profile -h 获取帮助。

kubectl -n aibrix-system port-forward svc/aibrix-redis-master 6379:6379 1>/dev/null 2>&1 &
# Wait for port-forward taking effect.
aibrix_gen_profile deepseek-coder-7b-v100 --cost [cost1] [SLO-metric] [SLO-value] -o "redis://:6379/?model=deepseek-coder-7b"
aibrix_gen_profile deepseek-coder-7b-l20 --cost [cost2] [SLO-metric] [SLO-value] -o "redis://:6379/?model=deepseek-coder-7b"

现在GPU优化器已准备就绪。您应该观察到工作负载Pod的数量会随着发送到网关的请求而变化。一旦GPU优化器完成扩展优化,GPU优化器的输出将通过指定的HTTP端点作为metricSource传递给PodAutoscaler,以进行最终的扩展决策。以下是PodAutoscaler规范的示例。

V100 GPU的PodAutoscaler规范的简单示例如下

apiVersion: autoscaling.aibrix.ai/v1alpha1
kind: PodAutoscaler
metadata:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: aibrix
  annotations:
    kpa.autoscaling.aibrix.ai/scale-down-delay: 0s
  name: podautoscaler-deepseek-coder-7b-v100
  namespace: default
spec:
  maxReplicas: 10
  metricsSources:
  - endpoint: aibrix-gpu-optimizer.aibrix-system.svc.cluster.local:8080
    metricSourceType: domain
    path: /metrics/default/deepseek-coder-7b-v100
    protocolType: http
    targetMetric: vllm:deployment_replicas
    targetValue: "100"  # For stable workloads. Set to a fraction to tolerate bursts.
  minReplicas: 0
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: deepseek-coder-7b-v100
  scalingStrategy: KPA

杂项#

添加了一个新的标签 model.aibrix.ai/min_replicas,用于指定在没有工作负载时要维护的最小副本数。我们建议至少将一个Deployment规范设置为1,以确保始终有一个READY的Pod可用。例如,尽管GPU优化器可能建议在没有活动期间v100 GPU的副本数为0,但设置 model.aibrix.ai/min_replicas: "1" 将维持一个v100副本。此标签仅在没有工作负载时影响系统——当存在活动请求时,它将被忽略。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deepseek-coder-7b-v100
  labels:
    model.aibrix.ai/name: "deepseek-coder-7b"
    model.aibrix.ai/min_replicas: "1" # min replica for gpu optimizer when no workloads.
... rest yaml deployments

重要提示:PodAutoscaler规范中的 minReplicas 字段必须设置为0,以允许正常的扩展行为。将其设置为任何大于0的值将干扰GPU优化器的扩展决策。例如,如果GPU优化器确定最佳配置为 {v100: 0, l20: 4},但v100 PodAutoscaler的 minReplicas: 1,系统将无法将v100按建议缩减到0。

路由支持#

在性能评估期间,我们观察到现有的路由策略未能充分考虑异构GPU不同的服务容量。具体来说,下图显示了当前路由策略未能遵守指定的服务级别目标(SLO)。

SLO Routing Motivation Plot

实验配置如下

  • SLO:每令牌P99延迟 ≤ 0.05秒。

  • 工作负载:混合工作负载,包括 ShareGPT (7 RPS) 和代码生成任务 (4 RPS),其特点是长提示(超过4K令牌)和短响应(32-64令牌)。

  • GPU:由NVIDIA A10和NVIDIA L20 GPU组成的异构GPU环境。

我们的实验表明,理想的路由场景(Oracle)将ShareGPT工作负载专门分配给A10 GPU,并将代码生成工作负载专门分配给L20 GPU。然而,现有的路由策略(woRouting)在A10和L20 GPU之间随机分配请求,未能复制这种理想场景。为了进行比较,我们还评估了一种所有请求均由性能更强的L20 GPU(Scalar)处理的场景。结果表明,尽管GPU优化器可以识别最佳GPU配置(Oracle Cost),但当前路由策略导致显著的性能下降、网关队列累积、不稳定的GPU配置以及持续违反SLO。

SLO路由策略在v0.4.0版本中引入,旨在解决异构GPU部署中的性能问题。请求必须显式指定 routing-strategy: slo 头部以启用SLO路由策略。此外,要有效激活此策略,需要每个工作负载在每个GPU上的性能分析数据。

以下显示了一个应用SLO路由策略的请求示例

curl -v https://:8888/v1/chat/completions \
            -H "model: llama2-7b" \
            -H "Content-Type: application/json" \
            -H "Authorization: Bearer [api_key]" \
            -H "routing-strategy: slo" \
            -d '{ \
                    "model": "llama2-7b", \
                    "messages": [{"role": "user", "content": "Say this is a test!"}], \
                    "temperature": 0.7 \
            }'

在相同的实验设置下,SLO路由策略展示了其实现目标性能的能力。

SLO Routing Motivation Plot

SLO路由策略目前支持三种变体:slo-pack-loadslo-least-loadslo-least-load-pulling``(当指定 ``slo 时的默认策略)。每个变体都将请求路由到可能满足其各自SLO的GPU,但在处理相同类型GPU之间的请求方面有所不同

  • slo-pack-load:如果性能分析表明没有违反SLO,则倾向于将请求整合到单个GPU上。

  • slo-least-load:倾向于将请求路由到相同类型中负载最小的GPU,忽略性能分析中的SLO违反预测。

  • slo-least-load-pulling:倾向于将请求路由到相同类型中负载最小的GPU。预计将违反SLO的请求在网关处排队,如果SLO已被违反则拒绝。

下图比较了 slo/slo-least-load-pullingslo-pack-load 变体的性能。least-request 策略用作公平比较的基线。

SLO Routing Motivation Plot