Todos os produtos
Search
Central de documentação

Alibaba Cloud Service Mesh:Use dynamic subset load balancing to accelerate Model Service Mesh inference

Última atualização: Jun 28, 2026

Em uma implantação do Model Service Mesh com múltiplos modelos, um serviço Kubernetes distribui as solicitações de inferência aleatoriamente entre todos os runtimes de serviço de modelo. Se uma solicitação chegar a um runtime que não hospeda o modelo alvo, o Model Service Mesh a redireciona internamente até encontrar o runtime correto. Esse redirecionamento aumenta a latência.

O balanceamento de carga por subconjunto dinâmico resolve esse problema ao agrupar os runtimes com base nos modelos que hospedam. Quando uma solicitação de inferência chega ao gateway do Service Mesh (ASM), ele lê o nome do modelo no cabeçalho da solicitação e a encaminha diretamente para um runtime que hospeda esse modelo. Isso elimina o redirecionamento e reduz a latência de inferência.

Para obter uma visão geral do conceito, consulte Balanceamento de carga por subconjunto dinâmico.

Como funciona

O balanceamento de carga por subconjunto dinâmico depende de dois recursos do Istio: uma DestinationRule define quais runtimes agrupar e uma VirtualService define como corresponder as solicitações a esses grupos.

  • A DestinationRule agrupa os runtimes em subconjuntos. O ASM estende a DestinationRule padrão com o campo dynamicSubset, que agrupa endpoints por uma chave de rótulo. O Model Service Mesh atualiza automaticamente os rótulos dos runtimes conforme os modelos são carregados ou descarregados, mantendo os subconjuntos atualizados sem intervenção manual.

  • A VirtualService corresponde às solicitações recebidas aos subconjuntos. O ASM estende a VirtualService padrão com o campo headerToDynamicSubsetKey, que mapeia um cabeçalho de solicitação (como model) para a chave de rótulo do subconjunto dinâmico. O gateway usa esse mapeamento para rotear cada solicitação ao subconjunto correto.

Se nenhum subconjunto corresponder à solicitação, a fallbackPolicy determina o comportamento:

Política de fallback

Comportamento

ANY_ENDPOINT

Roteia para qualquer runtime disponível, independentemente dos rótulos. Preserva a disponibilidade ao custo de possível redirecionamento. Utilizada neste tutorial.

Pré-requisitos

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

Etapa 1: Implantar um segundo modelo

O balanceamento de carga por subconjunto dinâmico é voltado para cenários com múltiplos modelos. Esta etapa adiciona um modelo tf-mnist (um modelo MNIST baseado em TensorFlow servido pelo runtime Triton) juntamente com o modelo sklearn-mnist existente.

Nota

Esta etapa utiliza a persistent volume claim (PVC) my-models-pvc criada em Usar o Model Service Mesh para lançar um serviço de inferência multimodelo. O conteúdo do modelo tf-mnist compreende tudo dentro do diretório mnist.

Armazenar o modelo no volume persistente

  1. Conecte-se ao cluster ACK com kubectl e copie o diretório do modelo mnist para o volume persistente:

    kubectl -n modelmesh-serving cp mnist pvc-access:/mnt/models/
  2. Verifique se o modelo existe no volume persistente:

    kubectl -n modelmesh-serving exec -it pvc-access -- ls -alr /mnt/models/

    Saída esperada:

    -rw-r--r-- 1  502 staff 344817 Apr 23 08:17 mnist-svm.joblib
    drwxr-xr-x 3 root root    4096 Apr 23 08:23 mnist
    drwxr-xr-x 1 root root    4096 Apr 23 08:17 ..
    drwxrwxrwx 3 root root    4096 Apr 23 08:23 .

Implantar o serviço de inferência

  1. Crie um arquivo chamado tf-mnist.yaml com o seguinte conteúdo:

    apiVersion: serving.kserve.io/v1beta1
    kind: InferenceService
    metadata:
      name: tf-mnist
      namespace: modelmesh-serving
      annotations:
        serving.kserve.io/deploymentMode: ModelMesh
    spec:
      predictor:
        model:
          modelFormat:
            name: tensorflow
          storage:
            parameters:
              type: pvc
              name: my-models-pvc
            path: mnist
  2. Aplique o manifesto:

    kubectl apply -f tf-mnist.yaml
  3. Aguarde o download da imagem e verifique se ambos os modelos estão prontos:

    kubectl get isvc -n modelmesh-serving

    Saída esperada:

    NAME            URL                                               READY
    sklearn-mnist   grpc://modelmesh-serving.modelmesh-serving:8033   True
    tf-mnist        grpc://modelmesh-serving.modelmesh-serving:8033   True

(Opcional) Etapa 2: Medir a latência de inferência antes da otimização

Use o fortio para medir a latência de base antes de ativar o balanceamento de carga por subconjunto dinâmico. Para obter o endereço IP do gateway de entrada do ASM, consulte Integrar o KServe com o ASM para implementar serviços de inferência baseados em modelos nativos da nuvem com IA.

  1. Defina o IP do gateway e execute um teste de carga de 60 segundos no modelo tf-mnist:

    ASM_GW_IP="<your-asm-gateway-ip>"
    fortio load -jitter=False -H 'model: tf-mnist' -c 1 -qps 100 -t 60s -payload '{"inputs": [{ "name": "inputs", "shape": [1, 784], "datatype": "FP32", "contents": { "fp32_contents": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01176471, 0.07058824, 0.07058824, 0.07058824, 0.49411765, 0.53333336, 0.6862745, 0.10196079, 0.6509804, 1.0, 0.96862745, 0.49803922, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.11764706, 0.14117648, 0.36862746, 0.6039216, 0.6666667, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.88235295, 0.6745098, 0.99215686, 0.9490196, 0.7647059, 0.2509804, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.19215687, 0.93333334, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.9843137, 0.3647059, 0.32156864, 0.32156864, 0.21960784, 0.15294118, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.07058824, 0.85882354, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.7764706, 0.7137255, 0.96862745, 0.94509804, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3137255, 0.6117647, 0.41960785, 0.99215686, 0.99215686, 0.8039216, 0.04313726, 0.0, 0.16862746, 0.6039216, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.05490196, 0.00392157, 0.6039216, 0.99215686, 0.3529412, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.54509807, 0.99215686, 0.74509805, 0.00784314, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.04313726, 0.74509805, 0.99215686, 0.27450982, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.13725491, 0.94509804, 0.88235295, 0.627451, 0.42352942, 0.00392157, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.31764707, 0.9411765, 0.99215686, 0.99215686, 0.46666667, 0.09803922, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1764706, 0.7294118, 0.99215686, 0.99215686, 0.5882353, 0.10588235, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0627451, 0.3647059, 0.9882353, 0.99215686, 0.73333335, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.9764706, 0.99215686, 0.9764706, 0.2509804, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.18039216, 0.50980395, 0.7176471, 0.99215686, 0.99215686, 0.8117647, 0.00784314, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.15294118, 0.5803922, 0.8980392, 0.99215686, 0.99215686, 0.99215686, 0.98039216, 0.7137255, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.09411765, 0.44705883, 0.8666667, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.7882353, 0.30588236, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.09019608, 0.25882354, 0.8352941, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.7764706, 0.31764707, 0.00784314, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.07058824, 0.67058825, 0.85882354, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.7647059, 0.3137255, 0.03529412, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.21568628, 0.6745098, 0.8862745, 0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.95686275, 0.52156866, 0.04313726, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.53333336, 0.99215686, 0.99215686, 0.99215686, 0.83137256, 0.5294118, 0.5176471, 0.0627451, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] }}]}' -a ${ASM_GW_IP}:8008/v2/models/tf-mnist/infer

    Saída esperada:

    Saída esperada

    16:06:53.107 r1 [INF] scli.go:125> Starting, command="Φορτίο", version="1.63.7 h1:S6e+z36nV6o8RYQSUI9EWYxhCoPJy4VdAB2HQROUqMg= go1.22.2 amd64 linux", go-max-procs=8
    Fortio 1.63.7 running at 100 queries per second, 8->8 procs, for 1m0s: 192.168.0.7:8008/v2/models/tf-mnist/infer
    16:06:53.107 r1 [INF] httprunner.go:121> Starting http test, run=0, url="192.168.0.7:8008/v2/models/tf-mnist/infer", threads=1, qps="100.0", warmup="parallel", conn-reuse=""
    16:06:53.107 r1 [WRN] http_client.go:170> Assuming http:// on missing scheme for '192.168.0.7:8008/v2/models/tf-mnist/infer'
    Starting at 100 qps with 1 thread(s) [gomax 8] for 1m0s : 6000 calls each (total 6000)
    16:07:53.172 r1 [INF] periodic.go:851> T000 ended after 1m0.007662555s : 6000 calls. qps=99.98723070575699
    Ended after 1m0.007716622s : 6000 calls. qps=99.987
    16:07:53.172 r1 [INF] periodic.go:581> Run ended, run=0, elapsed=60007716622, calls=6000, qps=99.98714061718327
    Sleep times : count 5999 avg 0.0021861297 +/- 0.001025 min -0.011550303 max 0.003734337 sum 13.1145918
    Aggregated Function Time : count 6000 avg 0.0072130591 +/- 0.0007502 min 0.006125677 max 0.020551562 sum 43.2783545
    # range, mid point, percentile, count
    >= 0.00612568 <= 0.007 , 0.00656284 , 35.88, 2153
    > 0.007 <= 0.008 , 0.0075 , 90.85, 3298
    > 0.008 <= 0.009 , 0.0085 , 97.77, 415
    > 0.009 <= 0.01 , 0.0095 , 99.42, 99
    > 0.01 <= 0.011 , 0.0105 , 99.68, 16
    > 0.011 <= 0.012 , 0.0115 , 99.77, 5
    > 0.012 <= 0.014 , 0.013 , 99.90, 8
    > 0.014 <= 0.016 , 0.015 , 99.95, 3
    > 0.016 <= 0.018 , 0.017 , 99.97, 1
    > 0.018 <= 0.02 , 0.019 , 99.98, 1
    > 0.02 <= 0.0205516 , 0.0202758 , 100.00, 1
    # target 50% 0.00725682
    # target 75% 0.00771164
    # target 90% 0.00798454
    # target 99% 0.00974747
    # target 99.9% 0.014
    Error cases : no data
    # Socket and IP used for each connection:
    [0]   1 socket used, resolved to 192.168.0.7:8008, connection timing : count 1 avg 0.004218262 +/- 0 min 0.004218262 max 0.004218262 sum 0.004218262
    Connection time histogram (s) : count 1 avg 0.004218262 +/- 0 min 0.004218262 max 0.004218262 sum 0.004218262
    # range, mid point, percentile, count
    >= 0.00421826 <= 0.00421826 , 0.00421826 , 100.00, 1
    # target 50% 0.00421826
    # target 75% 0.00421826
    # target 90% 0.00421826
    # target 99% 0.00421826
    # target 99.9% 0.00421826
    Sockets used: 1 (for perfect keepalive, would be 1)
    Uniform: false, Jitter: false, Catchup allowed: true
    IP addresses distribution:
    192.168.0.7:8008: 1
    Code 200 : 6000 (100.0 %)
    Response Header Sizes : count 6000 avg 233.00067 +/- 0.02581 min 233 max 234 sum 1398004
    Response Body/Total Sizes : count 6000 avg 454.00067 +/- 0.02581 min 454 max 455 sum 2724004
    All done 6000 calls (plus 1 warmup) 7.213 ms avg, 100.0 qps
    Successfully wrote 11561 bytes of Json data to 2024-04-24-160653_192_168_0_7_8008_v2_models_tf_mnist_infer_iZbp1jfq2w26u2kpxa9r3dZ.json
  2. Visualize os resultados do fortio em um navegador:

    fortio server

    Abra localhost:8080, clique em saved results e selecione o arquivo JSON para visualizar a distribuição de latência.

    Latency distribution before optimization

    Sem o balanceamento de carga por subconjunto dinâmico, algumas solicitações de inferência apresentam maior latência porque o Model Service Mesh as redireciona antes de alcançarem o runtime correto.

Etapa 3: Ative o balanceamento de carga por subconjunto dinâmico

As solicitações de inferência chegam ao Model Service Mesh através do serviço modelmesh-serving no namespace modelmesh-serving. Configure uma DestinationRule e uma VirtualService nesse serviço para rotear as solicitações diretamente ao runtime de serviço de modelo correto.

Crie a DestinationRule

Aplique a seguinte DestinationRule para agrupar dinamicamente os runtimes de serviço de modelo pelos modelos que hospedam. Para mais informações, consulte Gerencie regras de destino.

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: modelmesh-serving
  namespace: modelmesh-serving
spec:
  host: modelmesh-serving
  trafficPolicy:
    loadBalancer:
      dynamicSubset:
        subsetSelectors:
          - fallbackPolicy: ANY_ENDPOINT
            keys:
              - modelmesh.asm.alibabacloud.com

Campos principais:

Campo

Finalidade

dynamicSubset

Permite o agrupamento dinâmico de endpoints com base em rótulos de runtime, em vez de definições estáticas de subconjuntos

keys

Chave de rótulo usada para agrupar os runtimes. O Model Service Mesh define o rótulo modelmesh.asm.alibabacloud.com em cada runtime para indicar quais modelos ele hospeda

fallbackPolicy: ANY_ENDPOINT

Quando nenhum subconjunto corresponde, roteia para qualquer runtime disponível em vez de rejeitar a solicitação

Atualize a VirtualService

Aplique a seguinte VirtualService para mapear o cabeçalho de solicitação model para a chave do subconjunto dinâmico. Para mais informações, consulte Gerencie serviços virtuais.

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vs-modelmesh-serving-service
  namespace: modelmesh-serving
spec:
  gateways:
    - grpc-gateway
  hosts:
    - '*'
  http:
    - headerToDynamicSubsetKey:
        - header: model
          key: modelmesh.asm.alibabacloud.com
      match:
        - port: 8008
      name: default
      route:
        - destination:
            host: modelmesh-serving
            port:
              number: 8033

O campo headerToDynamicSubsetKey é uma extensão do ASM para a VirtualService padrão do Istio. Quando o gateway recebe uma solicitação com o cabeçalho model: tf-mnist, ele consulta o valor no rótulo modelmesh.asm.alibabacloud.com e roteia a solicitação para um runtime no subconjunto dinâmico correspondente.

(Opcional) Etapa 4: Medir a latência de inferência após a otimização

Execute o mesmo teste do fortio da Etapa 2 para comparar a latência.

Latency distribution after optimization

Após ativar o balanceamento de carga por subconjunto dinâmico, todas as solicitações de inferência são roteadas diretamente para o runtime correto. A distribuição de latência torna-se significativamente mais concentrada, sem valores discrepantes causados por redirecionamentos internos.