When managing LLM inference services with highly dynamic load, use inference framework custom metrics with Kubernetes HPA to automatically adjust Pod counts and improve service quality and stability.
How it works
LLM inference is bottlenecked by GPU compute and memory, not CPU or RAM. Scaling on GPU utilization or memory usage is misleading — a GPU at 90% may be idle-waiting on a long decode, not processing requests. Frameworks like vLLM, SGLang, and Dynamo expose load metrics such as waiting requests (num_requests_waiting) and KV cache usage (kv_cache_usage_perc). These are the right scaling signals.
The scaling pipeline:
-
A PodMonitor instructs Managed Service for Prometheus to scrape metrics from inference pods.
-
The
ack-alibaba-cloud-metrics-adapterbridges Prometheus metrics to the Kubernetes Custom Metrics API. -
The HPA reads custom metrics from that API and scales your StatefulSet up or down.
Prerequisites
Ensure the following:
-
A standalone or distributed inference service deployed in your cluster. See Deploy a standalone LLM inference service or Deploy a distributed LLM inference service
-
Managed Service for Prometheus enabled in your ACK cluster
-
The ack-alibaba-cloud-metrics-adapter component installed, with its
AlibabaCloudMetricsAdapter.prometheus.urlparameter pointing to your Managed Service for Prometheus endpoint. See Modify the configuration of the ack-alibaba-cloud-metrics-adapter component
Billing
Using Managed Service for Prometheus causes your service to emit custom metrics, which may incur additional fees. Fees vary based on your cluster size, number of applications, and data volume. To monitor your usage, see query usage data.
Step 1: Configure metric collection
If you already configured monitoring for LLM inference services, skip this step.
Create a PodMonitor to instruct Prometheus to scrape metrics from your inference pods.
-
Create a
podmonitor.yamlfile: -
Apply the configuration:
kubectl apply -f ./podmonitor.yaml
Step 2: Configure ack-alibaba-cloud-metrics-adapter
Configure the metrics adapter to expose inference metrics through the Kubernetes Custom Metrics API. Each metric rule has two fields:
-
seriesQuery: selects Prometheus time series (filtered by label selectors such asnamespaceandpod) -
metricsQuery: aggregates those series (typicallysum ... by (<<.GroupBy>>))
-
Log on to the ACK console. In the left navigation pane, click Clusters.
-
On the Clusters page, click the target cluster name. In the left navigation pane, choose Applications > Helm.
-
On the Helm page, find ack-alibaba-cloud-metrics-adapter and click Update in the Actions column.
-
In the Update Release panel, update the YAML configuration, then click OK. The example below covers vLLM, SGLang, and Dynamo metrics. Include only metrics for your framework. For all available metrics, see vLLM metrics, SGLang production metrics, and Dynamo metrics.
These metrics are examples. Modify based on your framework and scaling needs.
-
Verify the adapter exposes metrics. Query each configured metric:
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/vllm:num_requests_waiting"A successful response returns a JSON object with a
valuefield per pod. If this fails, check that the PodMonitor is deployed and Prometheus is scraping your inference pods.
Step 3: Configure HPA
Create an HPA that targets your inference StatefulSet and scales based on a custom metric.
Parameter values below are examples. Set thresholds based on your performance testing, costs, and SLOs. LLM inference pods start slowly, and requests can run for minutes. To prevent premature scale-down, configure behavior.scaleDown.stabilizationWindowSeconds. Default: 300 seconds. Increase for workloads with requests exceeding five minutes.
-
Create an
hpa.yamlfile. Use the example for your inference framework.vLLM
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: llm-inference-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: StatefulSet name: vllm-inference # Replace with your vLLM inference service name. minReplicas: 1 maxReplicas: 3 metrics: - type: Pods pods: metric: name: vllm:num_requests_waiting target: type: Value averageValue: 5 behavior: scaleDown: stabilizationWindowSeconds: 300 # Adjust based on your longest expected request duration.SGLang
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: llm-inference-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: StatefulSet name: sgl-inference minReplicas: 1 maxReplicas: 3 metrics: - type: Pods pods: metric: name: sglang:num_queue_reqs target: type: Value averageValue: 5 behavior: scaleDown: stabilizationWindowSeconds: 300 # Adjust based on your longest expected request duration. -
Apply the HPA:
kubectl apply -f hpa.yaml
Step 4: Test the auto scaling configuration
Load-test your inference service to trigger the HPA.
For benchmark tools, see the vLLM Benchmark guide and SGLang Benchmark guide.
-
Create a
benchmark.yamlfile. Set theimagefield to match your inference framework:-
vLLM:
kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/vllm:v0.10.0 -
SGLang:
anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/anolis-docker-images/docker-temp:0.3.4.post2-sglang0.4.10.post2-pytorch2.7.1.8-cuda12.8.1-py312-alinux3.2104
-
-
Deploy the benchmark pod:
kubectl create -f benchmark.yaml -
Run the benchmark from the client pod to load-test your inference service.
vLLM
python3 $VLLM_ROOT_DIR/benchmarks/benchmark_serving.py \ --model /models/Qwen3-32B \ --host inference-service \ --port 8000 \ --dataset-name random \ --random-input-len 1500 \ --random-output-len 100 \ --random-range-ratio 1 \ --num-prompts 400 \ --max-concurrency 20SGLang
python3 -m sglang.bench_serving --backend sglang \ --model /models/Qwen3-32B \ --host inference-service \ --port 8000 \ --dataset-name random \ --random-input-len 1500 \ --random-output-len 100 \ --random-range-ratio 1 \ --num-prompts 400 \ --max-concurrency 20 -
During the load test, check HPA status in a new terminal:
kubectl describe hpa llm-inference-hpaWhen average waiting requests exceed the threshold, HPA scales up the StatefulSet. A successful scale-up shows a
SuccessfulRescaleevent:Name: llm-inference-hpa Namespace: default Labels: <none> Annotations: <none> CreationTimestamp: Fri, 25 Jul 2025 11:29:20 +0800 Reference: StatefulSet/vllm-inference Metrics: ( current / target ) "vllm:num_requests_waiting" on pods: 11 / 5 Min replicas: 1 Max replicas: 3 StatefulSet pods: 1 current / 3 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True SucceededRescale the HPA controller was able to update the target scale to 3 ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric vllm:num_requests_waiting ScalingLimited False DesiredWithinRange the desired count is within the acceptable range Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 1s horizontal-pod-autoscaler New size: 3; reason: pods metric vllm:num_requests_waiting above target
Next steps
-
Tune your scaling thresholds with the full metrics list: vLLM metrics, SGLang production metrics, and Dynamo metrics