Todos os produtos
Search
Central de documentação

Alibaba Cloud Service Mesh:Smart routing with queues, KV Cache, and LoRA

Última atualização: Jun 28, 2026

O balanceamento de carga tradicional distribui requisições uniformemente entre os backends, mas as cargas de trabalho de inferência de LLM são inerentemente desiguais. Um prompt curto pode ser concluído em milissegundos, enquanto uma conclusão longa ocupa uma GPU por vários segundos. O Service Mesh (ASM) resolve esse problema roteando requisições com base no estado em tempo real de cada backend vLLM: profundidade da fila de requisições e utilização do cache KV. O resultado é um menor tempo até o primeiro token (TTFT), maior throughput e utilização equilibrada da GPU em todo o seu parque de inferência.

Este tópico orienta você na implantação de um serviço de inferência Llama 2 baseado em vLLM, na configuração de roteamento com reconhecimento de LLM por meio do ASM e na criação de painéis de observabilidade para monitorar o tráfego de inferência.

Importante

Atualmente, apenas serviços de inferência de LLM baseados em vLLM têm suporte.

Contexto

Modelos de linguagem grandes (LLMs)

Os modelos de linguagem grandes (LLMs) são modelos de linguagem baseados em redes neurais com bilhões de parâmetros, como GPT, Qwen e Llama. Esses modelos são treinados em conjuntos de dados diversificados e extensos — incluindo textos da web, literatura profissional e código — e são usados principalmente para tarefas de geração de texto, como conclusão e diálogo.

Para aproveitar os LLMs na criação de aplicações, você tem as seguintes opções:

  • Utilize serviços externos de API de LLM de plataformas como OpenAI, Alibaba Cloud Model Studio ou Moonshot.

  • Construa seus próprios serviços de inferência de LLM usando modelos e frameworks open-source ou proprietários, como o vLLM, e implante-os em um cluster Kubernetes. Essa abordagem é ideal para cenários que exigem controle sobre o serviço de inferência ou alta personalização das capacidades de inferência do LLM.

vLLM

O vLLM é um framework projetado para a construção eficiente e simplificada de serviços de inferência de LLM. Ele suporta diversos modelos de linguagem grandes, incluindo o Qwen, e otimiza a eficiência da inferência por meio de técnicas como PagedAttention, inferência em lote dinâmica (Continuous Batching) e quantização de modelos.

Como funciona o balanceamento de carga com reconhecimento de LLM

Por que o balanceamento de carga tradicional é insuficiente para inferência de LLM

Algoritmos clássicos, como round-robin e least-connections, presumem que cada requisição impõe uma carga semelhante. A inferência de LLM quebra essa premissa:

  • Tempo de processamento variável. Cada requisição passa por duas fases: prefill (codificação do prompt) e decode (geração de tokens um a um). A duração da fase de decode é imprevisível, pois o número de tokens de saída varia conforme a requisição.

  • Contenção de memória da GPU. O vLLM pré-aloca memória da GPU para o cache KV. À medida que o cache enche, o servidor coloca novas requisições em fila ou as transfere para a memória da CPU, o que aumenta drasticamente a latência.

Sem considerar esses fatores, as requisições se acumulam em alguns backends enquanto outros ficam ociosos, aumentando a latência de cauda e desperdiçando recursos da GPU.

Como o ASM roteia o tráfego de LLM

O ASM avalia métricas multidimensionais de cada backend vLLM para tomar decisões de roteamento:

Métrica

Fonte

Sinal de roteamento

Profundidade da fila de requisições

vllm:num_requests_waiting

Menos requisições na fila indicam processamento mais rápido

Utilização do cache KV

vllm:gpu_cache_usage_perc

Menor utilização significa mais memória da GPU disponível para novas requisições

Quando uma nova requisição chega, o ASM seleciona o backend com a melhor combinação desses sinais. Isso mantém a carga da GPU equilibrada entre as réplicas de inferência, reduz o TTFT e melhora o throughput geral em comparação aos algoritmos tradicionais.

Observabilidade do tráfego de LLM

Proxies padrão analisam cabeçalhos HTTP e caminhos de URL, mas ignoram o corpo da requisição. Como as APIs de inferência de LLM (formato compatível com OpenAI) carregam o nome do modelo e os parâmetros de token no corpo da requisição, a observabilidade tradicional perde dimensões críticas.

O ASM estende a observabilidade para o tráfego de inferência de LLM:

  • Os logs de acesso incluem o nome do modelo e as contagens de tokens de entrada/saída por requisição.

  • As métricas de monitoramento adicionam uma dimensão model para análise por modelo.

  • As métricas de tokens (asm_llm_proxy_prompt_tokens, asm_llm_proxy_completion_tokens) rastreiam o consumo de tokens nas cargas de trabalho.

Pré-requisitos

Antes de começar, verifique se você possui:

Etapa 1: Implantar um serviço de inferência vLLM de exemplo

Implante um modelo Llama 2 servido pelo vLLM com múltiplos adaptadores LoRA. A implantação inclui um Kubernetes Service, um ConfigMap para o modelo de chat e um Deployment com 3 réplicas apoiadas por GPU.

Nota

A imagem do contêiner requer uma GPU com mais de 16 GiB de memória de vídeo. Use o tipo de GPU A10 para clusters ACK ou a GPU B de 8ª geração para clusters ACS. A T4 (16 GiB) não fornece memória suficiente. Para detalhes sobre o modelo, abra um ticket.

A imagem do LLM é grande. Armazene-a previamente no Alibaba Cloud Container Registry (ACR) e faça o pull pela rede interna para evitar downloads lentos pelo endpoint público.

  1. Crie um arquivo chamado vllm-service.yaml com o seguinte conteúdo.

    ACK cluster

       apiVersion: v1
       kind: Service
       metadata:
         name: vllm-llama2-7b-pool
       spec:
         selector:
           app: vllm-llama2-7b-pool
         ports:
         - protocol: TCP
           port: 8000
           targetPort: 8000
         type: ClusterIP
       ---
       apiVersion: v1
       kind: ConfigMap
       metadata:
         name: chat-template
       data:
         llama-2-chat.jinja: |
           {% if messages[0]['role'] == 'system' %}
             {% set system_message = '<<SYS>>\n' + messages[0]['content'] | trim + '\n<</SYS>>\n\n' %}
             {% set messages = messages[1:] %}
           {% else %}
               {% set system_message = '' %}
           {% endif %}
    
           {% for message in messages %}
               {% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}
                   {{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}
               {% endif %}
    
               {% if loop.index0 == 0 %}
                   {% set content = system_message + message['content'] %}
               {% else %}
                   {% set content = message['content'] %}
               {% endif %}
               {% if message['role'] == 'user' %}
                   {{ bos_token + '[INST] ' + content | trim + ' [/INST]' }}
               {% elif message['role'] == 'assistant' %}
                   {{ ' ' + content | trim + ' ' + eos_token }}
               {% endif %}
           {% endfor %}
       ---
       apiVersion: apps/v1
       kind: Deployment
       metadata:
         name: vllm-llama2-7b-pool
         namespace: default
       spec:
         replicas: 3
         selector:
           matchLabels:
             app: vllm-llama2-7b-pool
         template:
           metadata:
             annotations:
               prometheus.io/path: /metrics
               prometheus.io/port: '8000'
               prometheus.io/scrape: 'true'
             labels:
               app: vllm-llama2-7b-pool
           spec:
             containers:
               - name: lora
                 image: "registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/llama2-with-lora:v0.2"
                 imagePullPolicy: IfNotPresent
                 command: ["python3", "-m", "vllm.entrypoints.openai.api_server"]
                 args:
                 - "--model"
                 - "/model/llama2"
                 - "--tensor-parallel-size"
                 - "1"
                 - "--port"
                 - "8000"
                 - '--gpu_memory_utilization'
                 - '0.8'
                 - "--enable-lora"
                 - "--max-loras"
                 - "4"
                 - "--max-cpu-loras"
                 - "12"
                 - "--lora-modules"
                 - 'sql-lora=/adapters/yard1/llama-2-7b-sql-lora-test_0'
                 - 'sql-lora-1=/adapters/yard1/llama-2-7b-sql-lora-test_1'
                 - 'sql-lora-2=/adapters/yard1/llama-2-7b-sql-lora-test_2'
                 - 'sql-lora-3=/adapters/yard1/llama-2-7b-sql-lora-test_3'
                 - 'sql-lora-4=/adapters/yard1/llama-2-7b-sql-lora-test_4'
                 - 'tweet-summary=/adapters/vineetsharma/qlora-adapter-Llama-2-7b-hf-TweetSumm_0'
                 - 'tweet-summary-1=/adapters/vineetsharma/qlora-adapter-Llama-2-7b-hf-TweetSumm_1'
                 - 'tweet-summary-2=/adapters/vineetsharma/qlora-adapter-Llama-2-7b-hf-TweetSumm_2'
                 - 'tweet-summary-3=/adapters/vineetsharma/qlora-adapter-Llama-2-7b-hf-TweetSumm_3'
                 - 'tweet-summary-4=/adapters/vineetsharma/qlora-adapter-Llama-2-7b-hf-TweetSumm_4'
                 - '--chat-template'
                 - '/etc/vllm/llama-2-chat.jinja'
                 env:
                   - name: PORT
                     value: "8000"
                 ports:
                   - containerPort: 8000
                     name: http
                     protocol: TCP
                 livenessProbe:
                   failureThreshold: 2400
                   httpGet:
                     path: /health
                     port: http
                     scheme: HTTP
                   initialDelaySeconds: 5
                   periodSeconds: 5
                   successThreshold: 1
                   timeoutSeconds: 1
                 readinessProbe:
                   failureThreshold: 6000
                   httpGet:
                     path: /health
                     port: http
                     scheme: HTTP
                   initialDelaySeconds: 5
                   periodSeconds: 5
                   successThreshold: 1
                   timeoutSeconds: 1
                 resources:
                   limits:
                     nvidia.com/gpu: 1
                   requests:
                     nvidia.com/gpu: 1
                 volumeMounts:
                   - mountPath: /data
                     name: data
                   - mountPath: /dev/shm
                     name: shm
                   - mountPath: /etc/vllm
                     name: chat-template
             restartPolicy: Always
             schedulerName: default-scheduler
             terminationGracePeriodSeconds: 30
             volumes:
               - name: data
                 emptyDir: {}
               - name: shm
                 emptyDir:
                   medium: Memory
               - name: chat-template
                 configMap:
                   name: chat-template

    ACS cluster

       apiVersion: v1
       kind: Service
       metadata:
         name: vllm-llama2-7b-pool
       spec:
         selector:
           app: vllm-llama2-7b-pool
         ports:
         - protocol: TCP
           port: 8000
           targetPort: 8000
         type: ClusterIP
       ---
       apiVersion: v1
       kind: ConfigMap
       metadata:
         name: chat-template
       data:
         llama-2-chat.jinja: |
           {% if messages[0]['role'] == 'system' %}
             {% set system_message = '<<SYS>>\n' + messages[0]['content'] | trim + '\n<</SYS>>\n\n' %}
             {% set messages = messages[1:] %}
           {% else %}
               {% set system_message = '' %}
           {% endif %}
    
           {% for message in messages %}
               {% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}
                   {{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}
               {% endif %}
    
               {% if loop.index0 == 0 %}
                   {% set content = system_message + message['content'] %}
               {% else %}
                   {% set content = message['content'] %}
               {% endif %}
               {% if message['role'] == 'user' %}
                   {{ bos_token + '[INST] ' + content | trim + ' [/INST]' }}
               {% elif message['role'] == 'assistant' %}
                   {{ ' ' + content | trim + ' ' + eos_token }}
               {% endif %}
           {% endfor %}
       ---
       apiVersion: apps/v1
       kind: Deployment
       metadata:
         name: vllm-llama2-7b-pool
         namespace: default
       spec:
         replicas: 3
         selector:
           matchLabels:
             app: vllm-llama2-7b-pool
         template:
           metadata:
             annotations:
               prometheus.io/path: /metrics
               prometheus.io/port: '8000'
               prometheus.io/scrape: 'true'
             labels:
               app: vllm-llama2-7b-pool
               alibabacloud.com/compute-class: gpu  # Specify GPU computing power
               alibabacloud.com/compute-qos: default
               alibabacloud.com/gpu-model-series: "example-model" # Replace with your GPU model series
           spec:
             containers:
               - name: lora
                 image: "registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/llama2-with-lora:v0.2"
                 imagePullPolicy: IfNotPresent
                 command: ["python3", "-m", "vllm.entrypoints.openai.api_server"]
                 args:
                 - "--model"
                 - "/model/llama2"
                 - "--tensor-parallel-size"
                 - "1"
                 - "--port"
                 - "8000"
                 - '--gpu_memory_utilization'
                 - '0.8'
                 - "--enable-lora"
                 - "--max-loras"
                 - "4"
                 - "--max-cpu-loras"
                 - "12"
                 - "--lora-modules"
                 - 'sql-lora=/adapters/yard1/llama-2-7b-sql-lora-test_0'
                 - 'sql-lora-1=/adapters/yard1/llama-2-7b-sql-lora-test_1'
                 - 'sql-lora-2=/adapters/yard1/llama-2-7b-sql-lora-test_2'
                 - 'sql-lora-3=/adapters/yard1/llama-2-7b-sql-lora-test_3'
                 - 'sql-lora-4=/adapters/yard1/llama-2-7b-sql-lora-test_4'
                 - 'tweet-summary=/adapters/vineetsharma/qlora-adapter-Llama-2-7b-hf-TweetSumm_0'
                 - 'tweet-summary-1=/adapters/vineetsharma/qlora-adapter-Llama-2-7b-hf-TweetSumm_1'
                 - 'tweet-summary-2=/adapters/vineetsharma/qlora-adapter-Llama-2-7b-hf-TweetSumm_2'
                 - 'tweet-summary-3=/adapters/vineetsharma/qlora-adapter-Llama-2-7b-hf-TweetSumm_3'
                 - 'tweet-summary-4=/adapters/vineetsharma/qlora-adapter-Llama-2-7b-hf-TweetSumm_4'
                 - '--chat-template'
                 - '/etc/vllm/llama-2-chat.jinja'
                 env:
                   - name: PORT
                     value: "8000"
                 ports:
                   - containerPort: 8000
                     name: http
                     protocol: TCP
                 livenessProbe:
                   failureThreshold: 2400
                   httpGet:
                     path: /health
                     port: http
                     scheme: HTTP
                   initialDelaySeconds: 5
                   periodSeconds: 5
                   successThreshold: 1
                   timeoutSeconds: 1
                 readinessProbe:
                   failureThreshold: 6000
                   httpGet:
                     path: /health
                     port: http
                     scheme: HTTP
                   initialDelaySeconds: 5
                   periodSeconds: 5
                   successThreshold: 1
                   timeoutSeconds: 1
                 resources:
                   limits:
                     cpu: 16
                     memory: 64Gi
                     nvidia.com/gpu: 1
                   requests:
                     cpu: 8
                     memory: 30Gi
                     nvidia.com/gpu: 1
                 volumeMounts:
                   - mountPath: /data
                     name: data
                   - mountPath: /dev/shm
                     name: shm
                   - mountPath: /etc/vllm
                     name: chat-template
             restartPolicy: Always
             schedulerName: default-scheduler
             terminationGracePeriodSeconds: 30
             volumes:
               - name: data
                 emptyDir: {}
               - name: shm
                 emptyDir:
                   medium: Memory
               - name: chat-template
                 configMap:
                   name: chat-template
  2. Implante o serviço de inferência.

       kubectl apply -f vllm-service.yaml
  3. Aguarde até que todas as 3 réplicas estejam prontas. Como a imagem do LLM é grande, os pulls iniciais podem levar vários minutos. Todos os 3 pods devem atingir o status Running com 1/1 contêineres prontos antes de você prosseguir.

       kubectl get pods -l app=vllm-llama2-7b-pool -w

Etapa 2: Configurar regras de gateway do ASM

Crie um recurso Gateway para habilitar o tráfego HTTP na porta 8080 do gateway de entrada do ASM.

  1. Crie um arquivo chamado gateway.yaml com o seguinte conteúdo.

       apiVersion: networking.istio.io/v1
       kind: Gateway
       metadata:
         name: llm-inference-gateway
         namespace: default
       spec:
         selector:
           istio: ingressgateway
         servers:
           - hosts:
               - '*'
             port:
               name: http-service
               number: 8080
               protocol: HTTP
  2. Aplique o recurso Gateway.

       kubectl apply -f gateway.yaml

Etapa 3: Configurar roteamento e balanceamento de carga para o serviço de inferência de LLM

Nota

Para comparar o balanceamento de carga com reconhecimento de LLM com o balanceamento tradicional, conclua as etapas em (Opcional) Comparar com o balanceamento de carga tradicional antes de prosseguir.

Esta etapa cria três recursos que conectam o gateway do ASM aos seus backends vLLM com roteamento inteligente para LLM:

Recurso

Finalidade

InferencePool

Agrupa Pods vLLM por seletor de rótulo e especifica a porta de inferência

InferenceModel

Mapeia nomes de modelos do corpo da requisição para Pods de backend e define a distribuição de tráfego

LLMRoute

Conecta o gateway do ASM ao InferencePool para roteamento com reconhecimento de LLM

Habilitar roteamento de inferência de LLM

Execute o seguinte comando usando o kubeconfig da sua instância do ASM:

kubectl patch asmmeshconfig default --type=merge \
  --patch='{"spec":{"gatewayAPIInferenceExtension":{"enabled":true}}}'

Criar o InferencePool

O InferencePool agrupa Pods vLLM por seletor de rótulo e especifica a porta de inferência.

  1. Crie um arquivo chamado inferencepool.yaml com o seguinte conteúdo.

    Campo

    Descrição

    .spec.targetPortNumber

    A porta em cada Pod que atende às requisições de inferência

    .spec.selector

    Seletor de rótulo correspondente aos Pods de inferência. A chave deve ser app e o valor deve corresponder ao nome do Serviço associado

       apiVersion: inference.networking.x-k8s.io/v1alpha1
       kind: InferencePool
       metadata:
         name: vllm-llama2-7b-pool
       spec:
         targetPortNumber: 8000
         selector:
           app: vllm-llama2-7b-pool
  2. Aplique o InferencePool usando o kubeconfig do cluster do plano de dados.

       kubectl apply -f inferencepool.yaml
  3. Verifique se o InferencePool está ativo. O status deve incluir Accepted=True e ResolvedRefs=True antes de você prosseguir.

       kubectl get inferencepool vllm-llama2-7b-pool -o yaml

Criar o InferenceModel

O InferenceModel mapeia o parâmetro model nas requisições recebidas para Pods de backend específicos e define os pesos de distribuição de tráfego.

  1. Crie um arquivo chamado inferencemodel.yaml com o seguinte conteúdo.

    Campo

    Descrição

    .spec.modelName

    Corresponde ao parâmetro model no corpo da requisição

    .spec.targetModels

    Define as regras de roteamento de tráfego. Neste exemplo, todas as requisições com model: tweet-summary são roteadas para Pods executando esse modelo

       apiVersion: inference.networking.x-k8s.io/v1alpha1
       kind: InferenceModel
       metadata:
         name: inferencemodel-sample
       spec:
         modelName: tweet-summary
         poolRef:
           group: inference.networking.x-k8s.io
           kind: InferencePool
           name: vllm-llama2-7b-pool
         targetModels:
         - name: tweet-summary
           weight: 100
  2. Aplique o InferenceModel.

       kubectl apply -f inferencemodel.yaml
  3. Verifique se o InferenceModel está ativo. O status deve incluir Accepted=True e ResolvedRefs=True.

       kubectl get inferencemodel inferencemodel-sample -o yaml

Criar o LLMRoute

O LLMRoute conecta o gateway do ASM ao InferencePool, encaminhando todas as requisições na porta 8080 para o serviço de inferência com balanceamento de carga consciente de LLM.

  1. Crie um arquivo chamado llmroute.yaml com o seguinte conteúdo.

       apiVersion: istio.alibabacloud.com/v1
       kind: LLMRoute
       metadata:
         name: test-llm-route
       spec:
         gateways:
         - llm-inference-gateway
         host: test.com
         rules:
         - backendRefs:
           - backendRef:
               group: inference.networking.x-k8s.io
               kind: InferencePool
               name: vllm-llama2-7b-pool
  2. Aplique o LLMRoute.

       kubectl apply -f llmroute.yaml

Etapa 4: Verificar a configuração

Envie uma requisição de teste através do gateway do ASM para confirmar que o roteamento com reconhecimento de LLM está funcionando.

curl -v \
  -H "host: test.com" \
  -H "Content-Type: application/json" \
  http://${ASM_GATEWAY_IP}:8080/v1/completions \
  -d '{
    "model": "tweet-summary",
    "prompt": "Write as if you were a critic: San Francisco",
    "max_tokens": 100,
    "temperature": 0
  }'

Substitua ${ASM_GATEWAY_IP} pelo endereço IP do seu gateway de entrada do ASM.

Uma resposta bem-sucedida se parece com isto:

{
  "id": "cmpl-2fc9a351-d866-422b-b561-874a30843a6b",
  "object": "text_completion",
  "created": 1736933141,
  "model": "tweet-summary",
  "choices": [
    {
      "index": 0,
      "text": "...",
      "logprobs": null,
      "finish_reason": "length",
      "stop_reason": null,
      "prompt_logprobs": null
    }
  ],
  "usage": {
    "prompt_tokens": 2,
    "total_tokens": 102,
    "completion_tokens": 100,
    "prompt_tokens_details": null
  }
}

Execute o comando várias vezes para observar que as requisições são distribuídas entre diferentes Pods de backend com base em sua carga em tempo real.

(Opcional) Etapa 5: Configurar observabilidade para serviços de inferência de LLM

Após configurar o InferencePool, InferenceModel e LLMRoute, configure o monitoramento para rastrear taxas de requisição de inferência, throughput de tokens e integridade dos backends vLLM.

Habilitar observabilidade de tráfego de LLM no ASM

  1. Habilite campos de log, métricas e dimensões de métricas específicos para LLM no console do ASM. Consulte Observação de tráfego: Gerencie eficientemente o tráfego de LLM usando o ASM para detalhes de configuração. Após a configuração, as métricas de monitoramento do ASM incluem uma dimensão model. Colete essas métricas usando:

  2. Adicione regras de coleta para as métricas de tokens específicas de LLM do ASM (asm_llm_proxy_prompt_tokens e asm_llm_proxy_completion_tokens) à sua configuração do Prometheus. Consulte Outras configurações de descoberta de serviço do Prometheus para detalhes de configuração.

       scrape_configs:
       - job_name: asm-envoy-stats-llm
         scrape_interval: 30s
         scrape_timeout: 30s
         metrics_path: /stats/prometheus
         scheme: http
         kubernetes_sd_configs:
         - role: pod
         relabel_configs:
         - source_labels:
           - __meta_kubernetes_pod_container_port_name
           action: keep
           regex: .*-envoy-prom
         - source_labels:
           - __address__
           - __meta_kubernetes_pod_annotation_prometheus_io_port
           action: replace
           regex: ([^:]+)(?::\d+)?;(\d+)
           replacement: $1:15090
           target_label: __address__
         - action: labelmap
           regex: __meta_kubernetes_pod_label_(.+)
         - source_labels:
           - __meta_kubernetes_namespace
           action: replace
           target_label: namespace
         - source_labels:
           - __meta_kubernetes_pod_name
           action: replace
           target_label: pod_name
         metric_relabel_configs:
         - action: keep
           source_labels:
           - __name__
           regex: asm_llm_.*

Coletar métricas de backend do vLLM

O serviço vLLM expõe métricas do Prometheus em /metrics na porta 8000. O Deployment de exemplo já inclui as anotações necessárias:

annotations:
  prometheus.io/path: /metrics
  prometheus.io/port: "8000"
  prometheus.io/scrape: "true"

O Prometheus descobre e coleta esses endpoints automaticamente por meio de seu mecanismo padrão de descoberta de serviço. Consulte Descoberta de serviço de pod padrão para detalhes.

Principais métricas do vLLM a serem monitoradas:

Métrica

Descrição

vllm:gpu_cache_usage_perc

Utilização do cache KV. Valores menores indicam mais memória da GPU disponível para novas requisições

vllm:request_queue_time_seconds_sum

Tempo que as requisições passam aguardando na fila antes que o agendador do vLLM execute prefill e decode

vllm:num_requests_running, vllm:num_requests_waiting, vllm:num_requests_swapped

Número de requisições executando inferência, aguardando na fila ou transferidas para a memória da CPU. Use-as para avaliar a pressão no backend

vllm:avg_generation_throughput_toks_per_s, vllm:avg_prompt_throughput_toks_per_s

Throughput de tokens para os estágios de decode e prefill por segundo

vllm:time_to_first_token_seconds_bucket

Distribuição do TTFT. Mede a rapidez com que os clientes recebem o primeiro token após enviar uma requisição — uma métrica chave para a latência percebida pelo usuário

Criar um painel do Grafana

Configure um painel do Grafana que combine métricas do ASM (taxa de requisição, throughput de tokens) com métricas do vLLM (cache da GPU, profundidade da fila, TTFT) para obter uma visão unificada do seu parque de inferência.

  1. Certifique-se de que sua fonte de dados do Prometheus no Grafana esteja coletando métricas tanto do ASM quanto do vLLM.

  2. Importe o JSON do painel fornecido abaixo para o Grafana. Baixe o JSON completo do painel na página de documentação do ASM (expanda Dashboard JSON nessa página para copiar o conteúdo completo).

  3. No Grafana, acesse Dashboards > Import, cole o JSON e selecione sua fonte de dados do Prometheus.

Grafana dashboard for LLM inference monitoring

(Opcional) Comparar com o balanceamento de carga tradicional

Use o painel de observabilidade para medir a diferença entre o balanceamento de carga com reconhecimento de LLM e o tradicional. Execute esta comparação antes de configurar o roteamento com reconhecimento de LLM na Etapa 3.

Nota

Se você já concluiu a Etapa 3, limpe primeiro os recursos de roteamento de LLM:

kubectl delete inferencemodel --all
kubectl delete inferencepool --all
kubectl delete llmroute --all
  1. Crie um VirtualService que roteie o tráfego usando o balanceamento de carga round-robin tradicional.

       kubectl apply -f- <<EOF
       apiVersion: networking.istio.io/v1
       kind: VirtualService
       metadata:
         name: llm-vs
         namespace: default
       spec:
         gateways:
           - default/llm-inference-gateway
         hosts:
           - '*'
         http:
           - name: any-host
             route:
               - destination:
                   host: vllm-llama2-7b-pool.default.svc.cluster.local
                   port:
                     number: 8000
       EOF
  2. Execute um teste de estresse contra o serviço de inferência usando uma ferramenta como o llmperf.

  3. Exclua o VirtualService e conclua a Etapa 3 para configurar o roteamento com reconhecimento de LLM. Certifique-se de que nenhum recurso VirtualService reste antes de prosseguir. Execute o mesmo teste de estresse novamente.

  4. Compare os resultados no painel do Grafana. O balanceamento de carga com reconhecimento de LLM oferece:

    • Menor TTFT (tempo até o primeiro token)

    • Maior throughput de tokens

    • Utilização mais uniforme do cache KV entre as réplicas

Performance comparison: traditional vs. LLM-aware load balancing

Limpeza

Para remover todos os recursos criados neste tutorial:

# Delete LLM routing resources
kubectl delete inferencemodel --all
kubectl delete inferencepool --all
kubectl delete llmroute --all

# Delete the gateway
kubectl delete -f gateway.yaml

# Delete the inference service
kubectl delete -f vllm-service.yaml

Tópicos relacionados