all-MiniLM-L6-v2嵌入服务弹性伸缩:K8s HPA基于QPS+GPU利用率双指标

想象一下,你部署了一个轻量级的句子嵌入模型服务,用来处理文档检索、语义搜索或者智能客服的意图理解。白天业务高峰时,用户查询蜂拥而至,服务响应开始变慢,甚至超时;到了深夜,流量骤降,昂贵的GPU资源却还在空转,白白浪费成本。

这就是很多AI服务上线后面临的典型困境:资源供给与实时需求不匹配。手动调整副本数?反应太慢,运维成本高。只靠CPU/内存监控扩容?对于GPU密集型服务,这就像用体温计去测血压,根本不准确。

今天,我们就来解决这个问题。我将带你一步步实现一个基于QPS(每秒查询数)和GPU利用率双指标的Kubernetes HPA(水平Pod自动伸缩)方案,专门针对我们使用Ollama部署的all-MiniLM-L6-v2嵌入服务。这个方案能让你的服务像拥有“自动驾驶”能力一样,在流量洪峰时自动扩容保稳定,在闲时自动缩容省成本。

1. 为什么需要双指标HPA?理解核心痛点

在深入技术细节前,我们先搞清楚,为什么传统的单指标伸缩在AI服务上常常“失灵”。

1.1 单一指标的局限性

  • 只监控CPU/内存:对于all-MiniLM-L6-v2这类模型推理服务,主要的计算负载在GPU上。CPU和内存的占用可能一直很平稳,即使GPU已经“烧”起来了,服务响应变慢,HPA也不会触发扩容。这会导致用户体验下降。
  • 只监控QPS:QPS高确实代表请求多,需要更多实例。但如果单个请求非常复杂(比如超长文本),或者模型正在加载,即使QPS不高,单个Pod也可能已经不堪重负(GPU利用率爆表)。这时仅凭QPS扩容是不够的,需要基于GPU负载增加实例来分担压力。
  • 只监控GPU利用率:GPU利用率高,可能是因为后台在跑训练任务,或者某个批处理任务。如果此时真实的用户请求(QPS)很少,盲目扩容只会增加资源浪费。

1.2 双指标协同的优势

QPSGPU利用率结合起来,就像给服务装上了“需求雷达”和“健康监测仪”:

  1. QPS作为需求驱动指标:它直接反映了外部用户的请求压力。QPS升高,是扩容最直接、最根本的信号。
  2. GPU利用率作为资源健康指标:它反映了单个服务实例的内部负载情况。即使QPS暂时不高,但GPU利用率持续高位,说明当前实例处理能力已达瓶颈,也需要扩容来预防潜在风险。
  3. 协同决策:HPA会同时计算两个指标所需的副本数,然后取其中的最大值作为最终伸缩目标。这确保了服务既能应对流量高峰,也能保证每个实例的健康运行状态。

我们的目标,就是让服务副本数 N = max(基于QPS算出的副本数, 基于GPU利用率算出的副本数)

2. 环境与部署准备

在搭建自动伸缩体系之前,我们需要一个稳定运行的服务作为基础。

2.1 部署all-MiniLM-L6-v2嵌入服务

我们使用Ollama来部署和管理模型,它非常轻量且容器友好。假设你已经有一个Kubernetes集群,并且安装了NVIDIA GPU Operator等必要的GPU支持组件。

首先,创建一个Kubernetes Deployment来运行Ollama服务并拉取all-MiniLM-L6-v2模型。

# deployment-ollama-embedding.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ollama-embedding
  namespace: ai-services
spec:
  replicas: 2 # 初始副本数,HPA会从这个值开始调整
  selector:
    matchLabels:
      app: ollama-embedding
  template:
    metadata:
      labels:
        app: ollama-embedding
    spec:
      containers:
      - name: ollama
        image: ollama/ollama:latest
        ports:
        - containerPort: 11434
        resources:
          limits:
            nvidia.com/gpu: 1 # 申请1块GPU
            memory: "4Gi"
            cpu: "2"
          requests:
            nvidia.com/gpu: 1
            memory: "2Gi"
            cpu: "1"
        volumeMounts:
        - name: ollama-data
          mountPath: /root/.ollama
        lifecycle:
          postStart:
            exec:
              command: ["/bin/sh", "-c", "ollama pull all-minilm-l6-v2 && ollama run all-minilm-l6-v2"]
      volumes:
      - name: ollama-data
        persistentVolumeClaim:
          claimName: ollama-pvc # 需要提前创建PVC,用于存储模型
---
# 创建一个Service,用于内部访问和指标暴露
apiVersion: v1
kind: Service
metadata:
  name: ollama-embedding-svc
  namespace: ai-services
spec:
  selector:
    app: ollama-embedding
  ports:
  - port: 11434
    targetPort: 11434
  type: ClusterIP

应用这个配置:

kubectl apply -f deployment-ollama-embedding.yaml

部署完成后,你可以通过端口转发测试服务是否正常:

kubectl port-forward svc/ollama-embedding-svc 11434:11434 -n ai-services

然后使用curl调用嵌入接口:

curl http://localhost:11434/api/embeddings -d '{
  "model": "all-minilm-l6-v2",
  "prompt": "What is the capital of France?"
}'

2.2 部署指标监控系统(Prometheus + Grafana)

HPA需要读取指标数据来做决策。我们需要部署Prometheus来收集指标,并通过prometheus-adapterkube-state-metrics等组件将自定义指标(如QPS)提供给K8s API。

这里假设使用Prometheus Operator(如kube-prometheus-stack)来简化部署。你需要确保Prometheus能够:

  1. 抓取Pod基础指标:通过cAdvisorkubelet
  2. 抓取GPU指标:安装dcgm-exporternvidia-dcgm,它会将GPU利用率、显存使用等指标暴露给Prometheus。
  3. 抓取应用QPS指标:这需要你的应用暴露一个Prometheus格式的/metrics端点。Ollama本身可能不直接提供,一个常见的做法是部署一个nginxenvoy作为sidecar代理,用它来统计请求速率,并暴露指标。或者,使用像prometheus-blackbox-exporter进行外部探测。

关键步骤:验证指标是否可被查询。在Prometheus的Web UI或通过Grafana中,你应该能查询到类似以下的指标:

  • GPU利用率:DCGM_FI_DEV_GPU_UTILnvidia_gpu_duty_cycle
  • HTTP请求速率(QPS):rate(nginx_http_requests_total{service="ollama-embedding"}[5m])
    • (这是一个示例,具体指标名取决于你的暴露方式)

3. 构建双指标HPA策略

这是最核心的部分。我们将创建一个HPA资源,它同时监听QPS和GPU利用率。

3.1 创建基于自定义指标的HPA

首先,确保你的集群已经安装了prometheus-adapter,并且已经将Prometheus中的自定义指标(如我们的QPS)注册到了Kubernetes的custom.metrics.k8s.io/v1beta1 API。

然后,创建HPA配置文件:

# hpa-ollama-dual-metrics.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ollama-embedding-hpa
  namespace: ai-services
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ollama-embedding
  minReplicas: 2 # 最小副本数,保证基本可用性
  maxReplicas: 10 # 最大副本数,根据集群资源设置
  metrics:
  # 指标1:基于QPS(每秒查询数)
  - type: Pods
    pods:
      metric:
        name: http_requests_per_second # 这是通过prometheus-adapter注册到K8s的自定义指标名
      target:
        type: AverageValue
        averageValue: 50 # 目标值:每个Pod平均每秒处理50个请求
  # 指标2:基于GPU利用率
  - type: Pods
    pods:
      metric:
        name: nvidia_gpu_duty_cycle # GPU利用率指标名,来自dcgm-exporter
      target:
        type: AverageValue
        averageValue: 60 # 目标值:每个Pod平均GPU利用率维持在60%
  behavior: # 伸缩行为配置,避免抖动
    scaleUp:
      stabilizationWindowSeconds: 60 # 扩容稳定窗口:指标持续达标60秒才扩容
      policies:
      - type: Percent
        value: 100
        periodSeconds: 60 # 每分钟最多扩容100%的当前副本数
    scaleDown:
      stabilizationWindowSeconds: 300 # 缩容稳定窗口:更谨慎,持续300秒才缩容
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60 # 每分钟最多缩容50%的当前副本数

参数解读

  • target.averageValue: 50:HPA会尽力维持每个Pod的QPS在50左右。如果总QPS是200,那么理想副本数就是200/50=4个。
  • target.averageValue: 60:HPA会尽力维持每个Pod的GPU利用率在60%左右。如果所有Pod的GPU利用率平均是80%,那么为了降到60%,就需要增加副本数来分摊负载。
  • behavior:这部分配置非常重要,它防止了因指标瞬时波动导致的Pod数量“抖动”。缩容比扩容更保守,避免过早回收资源导致性能下降。

应用HPA配置:

kubectl apply -f hpa-ollama-dual-metrics.yaml

3.2 验证与观察

创建后,通过以下命令观察HPA状态:

kubectl get hpa ollama-embedding-hpa -n ai-services -w

你会看到类似这样的输出,其中TARGETS列显示了当前指标值与目标值的比例,这是决策的关键:

NAME                     REFERENCE                         TARGETS                           MINPODS   MAXPODS   REPLICAS   AGE
ollama-embedding-hpa     Deployment/ollama-embedding      50075m/50 (avg), 108%/60% (avg)   2         10        4          5m
  • 50075m/50 (avg):当前每个Pod的QPS是50.075,目标值是50,比例约为100%(已达标)。
  • 108%/60% (avg):当前每个Pod的GPU利用率是108%,目标值是60%,比例是180%,严重超标。
  • HPA会计算两个指标所需的副本数,取最大值。假设当前是2个副本,那么:
    • 基于QPS:(50.075/50) * 2 replicas ≈ 2.003 replicas -> 2个副本
    • 基于GPU:(108/60) * 2 replicas = 3.6 replicas -> 4个副本 (向上取整)
  • 最终,HPA会将Pod副本数扩展到4个。

你可以使用kubectl describe hpa查看详细的伸缩事件和决策日志。

4. 实战测试与效果验证

理论再好,也需要实战检验。我们可以用简单的压测工具来模拟流量变化,观察HPA的反应。

4.1 模拟流量洪峰

使用heywrk等HTTP压测工具,向你的服务端点发起大量嵌入请求。

# 假设服务已通过Ingress或NodePort暴露
SERVICE_URL="http://your-ollama-service:11434/api/embeddings"

# 使用hey进行压测,持续300秒,每秒保持100个并发请求
hey -z 300s -c 100 -m POST -d '{"model":"all-minilm-l6-v2","prompt":"benchmarking text"}' $SERVICE_URL

4.2 观察伸缩过程

  1. 打开终端窗口1,监控HPA

    kubectl get hpa -n ai-services -w
    
  2. 打开终端窗口2,监控Pod变化

    kubectl get pods -n ai-services -l app=ollama-embedding -w
    
  3. 在Grafana中观察指标面板:创建或使用现有的面板,同时展示:

    • 总QPS和每个Pod的QPS
    • 每个Pod的GPU利用率
    • Pod副本数的变化曲线

预期效果

  • 压测开始后,总QPS和GPU利用率会迅速上升。
  • HPA的TARGETS列中,两个指标值会超过100%。
  • 经过scaleUp.stabilizationWindowSeconds(我们设为60秒)的稳定期后,你会看到REPLICAS数量开始增加,新的Pod进入Pending->ContainerCreating->Running状态。
  • 随着副本数增加,平均到每个Pod的QPS和GPU利用率会逐渐下降,向目标值靠拢。
  • 压测停止后,指标下降。经过更长的scaleDown.stabilizationWindowSeconds(300秒)后,多余的Pod会被逐渐回收,最终可能回到minReplicas

4.3 高级调优建议

  • 指标目标值(Target Value)50 QPS和60% GPU利用率只是起点。你需要根据实际业务场景、Pod的资源规格(GPU型号)和可接受的延迟来调整。可以通过历史负载分析找到一个平衡点。
  • 冷却窗口(Stabilization Window):这是防止“抖动”的关键。对于AI服务,模型加载需要时间,缩容尤其要谨慎。我们的设置(扩容60秒,缩容300秒)比较通用,你可以根据服务启动速度调整。
  • 就绪探针(Readiness Probe):确保在Deployment中配置了正确的就绪探针。HPA扩容出的新Pod,只有在就绪探针通过后,才会被纳入Service的负载均衡,开始接收流量。对于Ollama,可以检查/api/tags端点。
    readinessProbe:
      httpGet:
        path: /api/tags
        port: 11434
      initialDelaySeconds: 30 # 给模型加载留出足够时间
      periodSeconds: 10
    
  • 资源限制(Resources Limits):确保Deployment中设置的GPU、CPU、内存limitsrequests合理。HPA负责数量,而调度器(Scheduler)需要根据requests来寻找有足够资源的节点。

5. 总结

通过将QPS(业务需求)GPU利用率(资源健康) 这两个黄金指标结合,我们为all-MiniLM-L6-v2嵌入服务构建了一个真正智能的弹性伸缩方案。它不再是机械地响应单一信号,而是能综合判断服务的“忙闲”与“健康”状态,做出更合理的决策。

回顾一下关键收获:

  1. 双指标驱动更精准:避免了单一指标(如CPU)在GPU服务上失效的问题,同时响应外部流量和内部负载压力。
  2. Kubernetes HPA v2 API是强大工具:它支持丰富的指标类型和灵活的行为配置,是实现自动化的基石。
  3. 监控是前提:没有准确的指标,就没有正确的伸缩。务必确保Prometheus能稳定抓取到应用QPS和GPU利用率数据。
  4. 配置需要调优:目标值、冷却窗口、资源限制等参数都需要结合你的具体业务流量模式、硬件性能和SLA要求进行反复测试和调整。

这套方案不仅适用于Ollama部署的嵌入模型,其思想可以平移到任何需要基于业务量和资源利用率进行伸缩的AI推理服务上。实现服务的弹性化,是走向高效、稳定、低成本AIOps的关键一步。现在,你的嵌入服务已经具备了应对未知流量挑战的“自适应”能力。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐