all-MiniLM-L6-v2嵌入服务弹性伸缩:K8s HPA基于QPS+GPU利用率双指标
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 双指标协同的优势
将QPS和GPU利用率结合起来,就像给服务装上了“需求雷达”和“健康监测仪”:
- QPS作为需求驱动指标:它直接反映了外部用户的请求压力。QPS升高,是扩容最直接、最根本的信号。
- GPU利用率作为资源健康指标:它反映了单个服务实例的内部负载情况。即使QPS暂时不高,但GPU利用率持续高位,说明当前实例处理能力已达瓶颈,也需要扩容来预防潜在风险。
- 协同决策: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-adapter或kube-state-metrics等组件将自定义指标(如QPS)提供给K8s API。
这里假设使用Prometheus Operator(如kube-prometheus-stack)来简化部署。你需要确保Prometheus能够:
- 抓取Pod基础指标:通过
cAdvisor和kubelet。 - 抓取GPU指标:安装
dcgm-exporter或nvidia-dcgm,它会将GPU利用率、显存使用等指标暴露给Prometheus。 - 抓取应用QPS指标:这需要你的应用暴露一个Prometheus格式的/metrics端点。Ollama本身可能不直接提供,一个常见的做法是部署一个
nginx或envoy作为sidecar代理,用它来统计请求速率,并暴露指标。或者,使用像prometheus-blackbox-exporter进行外部探测。
关键步骤:验证指标是否可被查询。在Prometheus的Web UI或通过Grafana中,你应该能查询到类似以下的指标:
- GPU利用率:
DCGM_FI_DEV_GPU_UTIL或nvidia_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 模拟流量洪峰
使用hey或wrk等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,监控HPA:
kubectl get hpa -n ai-services -w -
打开终端窗口2,监控Pod变化:
kubectl get pods -n ai-services -l app=ollama-embedding -w -
在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):
50QPS和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、内存
limits和requests合理。HPA负责数量,而调度器(Scheduler)需要根据requests来寻找有足够资源的节点。
5. 总结
通过将QPS(业务需求) 和GPU利用率(资源健康) 这两个黄金指标结合,我们为all-MiniLM-L6-v2嵌入服务构建了一个真正智能的弹性伸缩方案。它不再是机械地响应单一信号,而是能综合判断服务的“忙闲”与“健康”状态,做出更合理的决策。
回顾一下关键收获:
- 双指标驱动更精准:避免了单一指标(如CPU)在GPU服务上失效的问题,同时响应外部流量和内部负载压力。
- Kubernetes HPA v2 API是强大工具:它支持丰富的指标类型和灵活的行为配置,是实现自动化的基石。
- 监控是前提:没有准确的指标,就没有正确的伸缩。务必确保Prometheus能稳定抓取到应用QPS和GPU利用率数据。
- 配置需要调优:目标值、冷却窗口、资源限制等参数都需要结合你的具体业务流量模式、硬件性能和SLA要求进行反复测试和调整。
这套方案不仅适用于Ollama部署的嵌入模型,其思想可以平移到任何需要基于业务量和资源利用率进行伸缩的AI推理服务上。实现服务的弹性化,是走向高效、稳定、低成本AIOps的关键一步。现在,你的嵌入服务已经具备了应对未知流量挑战的“自适应”能力。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐



所有评论(0)