すべてのプロダクト
Search
ドキュメントセンター

Container Compute Service:推論拡張機能を備えたゲートウェイを使用して、インテリジェントルーティングとトラフィック管理を実装する

最終更新日:Jul 28, 2025

Kubernetes クラスターの大規模言語モデル(LLM)推論サービスでは、従来のロードバランシング方法は単純なトラフィック割り当てに依存していることが多く、LLM 推論プロセス中の複雑なリクエストや動的なトラフィック負荷を処理できません。このトピックでは、推論拡張機能付きゲートウェイ を使用して推論サービス拡張機能を構成し、インテリジェントルーティングと効率的なトラフィック管理を実現する方法について説明します。

背景情報

大規模言語モデル(LLM)

大規模言語モデル(LLM)は、数十億のパラメーターを持つニューラルネットワークベースの言語モデルであり、GPT、Qwen、Llama などが代表的な例です。これらのモデルは、Web テキスト、専門文献、コードなど、多様で大規模な事前トレーニングデータセットでトレーニングされており、主に補完や対話などのテキスト生成タスクに使用されます。

LLM を活用してアプリケーションを構築するには、次のことができます。

  • OpenAI、Alibaba Cloud Model Studio、Moonshot などのプラットフォームから外部 LLM API サービスを利用する。

  • オープンソースまたは独自のモデルと vLLM などのフレームワークを使用して独自の LLM 推論サービスを構築し、Kubernetes クラスターにデプロイする。このアプローチは、推論サービスの制御や LLM 推論機能の高いカスタマイズが必要なシナリオに適しています。

vLLM

vLLM は、LLM 推論サービスを効率的かつユーザーフレンドリーに構築するために設計されたフレームワークです。 Qwen を含むさまざまな大規模言語モデルをサポートし、PagedAttention、動的バッチ推論(Continuous Batching)、モデル量子化などの手法により LLM 推論効率を最適化します。

KV キャッシュ

推論プロセス中に、モデルによって生成されたキーと値をキャッシュに保存して、履歴リクエストのコンテキスト情報にすばやくアクセスします。これにより、モデルによるテキスト生成の効率が向上します。 KV キャッシュを使用することで、冗長な計算を回避し、推論速度を向上させ、モデルの応答レイテンシを短縮できます。

手順

次の図はフローチャートです。

  1. inference-gateway では、ポート 8080 は標準の HTTP ルートで設定され、リクエストをバックエンド推論サービスに転送します。ポート 8081 は、リクエストを推論サービス拡張機能(LLM ルート)にルーティングし、そこからリクエストをバックエンド推論サービスに転送します。

  2. HTTP ルートでは、InferencePool リソースを使用して、クラスター内の LLM 推論サービスワークロードのグループを宣言します。 InferenceModel を構成して、InferencePool 内で選択されたモデルのトラフィック分散ポリシーを指定します。このようにして、inference-gateway コンポーネントのポート 8081 を介してルーティングされたリクエストは、推論サービス用に設計された拡張ロードバランシングアルゴリズムを使用して、InferencePool によって指定された推論サービスワークロードに転送されます。

前提条件

GPU ノードプールを持つ ACK マネージドクラスター が作成されていること。ACK マネージドクラスターに ACK Virtual Node コンポーネントをインストールして、ACK Pro クラスターで ACS の計算能力を使用する ことができます。

手順

ステップ 1: サンプル推論サービスをデプロイする

  1. vllm-service.yaml という名前のファイルを作成し、次の内容をファイルにコピーします。

    説明

    このトピックで使用されているイメージについては、ACK クラスターには A10 カード、Alibaba Cloud Container Compute Service (ACS) GPU 計算能力には GN8IS (第 8 世代 GPU B) カードを使用することをお勧めします。

    LLM イメージのサイズが大きいため、事前に Container Registry に転送し、内部ネットワークアドレスを使用してプルすることをお勧めします。パブリックネットワークからのプルの速度は、クラスターの Elastic IP アドレス (EIP) の帯域幅構成によって異なり、待機時間が長くなる可能性があります。

    YAML を表示

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: qwen
      name: qwen
    spec:
      progressDeadlineSeconds: 600
      replicas: 5
      selector:
        matchLabels:
          app: qwen
      template:
        metadata:
          annotations:
            prometheus.io/path: /metrics // メトリクスの公開先 HTTP パス
            prometheus.io/port: "8000" // メトリクスの公開ポート。vLLM サーバーのリスニングポート
            prometheus.io/scrape: "true" // 現在のポッドのメトリクスをスクレイプするかどうかを指定します
          labels:
            app: qwen
            alibabacloud.com/compute-class: gpu
            alibabacloud.com/compute-qos: default
            alibabacloud.com/gpu-model-series: GN8IS
        spec:
          containers:
            - command:
                - sh
                - -c
                - vllm serve /models/Qwen-2.5-7B-Instruct --port 8000 --trust-remote-code --served-model-name /model/qwen --gpu-memory-utilization 0.95 --enforce-eager --enable-lora --max-loras 2 --max-cpu-loras 4 --lora-modules travel-helper-v1=/models/Qwen-TravelHelper-Lora travel-helper-v2=/models/Qwen-TravelHelper-Lora-v2
              image: registry-cn-hangzhou.ack.aliyuncs.com/dev/qwen-2.5-7b-instruct-lora:v0.1
              imagePullPolicy: IfNotPresent
              name: custom-serving
              ports:
                - containerPort: 8000
                  name: http
                  protocol: TCP
              readinessProbe:
                failureThreshold: 3
                initialDelaySeconds: 30
                periodSeconds: 30
                successThreshold: 1
                tcpSocket:
                  port: 8000
                timeoutSeconds: 1
              resources:
                limits:
                  nvidia.com/gpu: "1"
                  cpu: "8"
                  memory: 30G
              terminationMessagePath: /dev/termination-log
              terminationMessagePolicy: File
              volumeMounts:
                - mountPath: /dev/shm
                  name: dshm
          restartPolicy: Always
          volumes:
            - emptyDir:
                medium: Memory
                sizeLimit: 30Gi
              name: dshm
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: qwen
      name: qwen
    spec:
      ports:
        - name: http-serving
          port: 8000
          protocol: TCP
          targetPort: 8000
      selector:
        app: qwen
  2. サンプル推論サービスをデプロイします。

    kubectl apply -f vllm-service.yaml

ステップ 2: 推論拡張機能付きゲートウェイ コンポーネントをインストールする推論拡張機能付きゲートウェイ<script>

推論拡張機能付きゲートウェイコンポーネントをインストールする で、[Gateway API 推論拡張を有効にする] を選択します。

image

ステップ 3: 推論ルーティングをデプロイする

このステップでは、InferencePool リソースと InferenceModel リソースを作成します。

  1. inference-pool.yaml という名前のファイルを作成します。

    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferencePool
    metadata:
      name: vllm-qwen-pool
    spec:
      targetPortNumber: 8000
      selector:
        app: qwen
      extensionRef:
        name: inference-gateway-ext-proc
    ---
    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferenceModel
    metadata:
      name: inferencemodel-qwen
    spec:
      modelName: /model/qwen
      criticality: Critical
      poolRef:
        group: inference.networking.x-k8s.io
        kind: InferencePool
        name: vllm-qwen-pool
      targetModels:
      - name: /model/qwen
        weight: 100
  2. 推論ルーティングをデプロイします。

    kubectl apply -f inference-gateway-llm.yaml

ステップ 4: ゲートウェイをデプロイして検証する

このステップでは、ポート 8080 と 8081 を含むゲートウェイを作成します。

  1. inference-gateway.yaml という名前のファイルを作成します。

    apiVersion: gateway.networking.k8s.io/v1
    kind: GatewayClass
    metadata:
      name: qwen-inference-gateway-class
    spec:
      controllerName: gateway.envoyproxy.io/gatewayclass-controller
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: qwen-inference-gateway
    spec:
      gatewayClassName: qwen-inference-gateway-class
      listeners:
        - name: http
          protocol: HTTP
          port: 8080
        - name: llm-gw
          protocol: HTTP
          port: 8081
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: qwen-backend
    spec:
      parentRefs:
        - name: qwen-inference-gateway
          sectionName: llm-gw
      rules:
        - backendRefs:
            - group: inference.networking.x-k8s.io
              kind: InferencePool
              name: vllm-qwen-pool
          matches:
            - path:
                type: PathPrefix
                value: /
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: qwen-backend-no-inference
    spec:
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: qwen-inference-gateway
        sectionName: http
      rules:
      - backendRefs:
        - group: ""
          kind: Service
          name: qwen
          port: 8000
          weight: 1
        matches:
        - path:
            type: PathPrefix
            value: /
    ---
    apiVersion: gateway.envoyproxy.io/v1alpha1
    kind: BackendTrafficPolicy
    metadata:
      name: backend-timeout
    spec:
      timeout:
        http:
          requestTimeout: 1h
      targetRef:
        group: gateway.networking.k8s.io
        kind: Gateway
        name: qwen-inference-gateway
  2. ゲートウェイをデプロイします。

    kubectl apply -f inference-gateway.yaml

    このステップでは、envoy-gateway-system という名前のネームスペースと、envoy-default-inference-gateway-645xxxxx という名前のサービスがクラスターに作成されます。

  3. ゲートウェイのパブリック IP アドレスを取得します。

    export GATEWAY_HOST=$(kubectl get gateway/qwen-inference-gateway -o jsonpath='{.status.addresses[0].value}')
  4. ゲートウェイがポート 8080 の標準 HTTP ルーティングを介して推論サービスにルーティングされていることを確認します。

    curl -X POST ${GATEWAY_HOST}:8080/v1/chat/completions -H 'Content-Type: application/json' -d '{
        "model": "/model/qwen",
        "max_completion_tokens": 100,
        "temperature": 0,
        "messages": [
          {
            "role": "user",
            "content": "Write as if you were a critic: San Francisco"
          }
        ]
    }'

    期待される出力:

    {"id":"chatcmpl-aa6438e2-d65b-4211-afb8-ae8e76e7a692","object":"chat.completion","created":1747191180,"model":"/model/qwen","choices":[{"index":0,"message":{"role":"assistant","reasoning_content":null,"content":"San Francisco, a city that has long been a beacon of innovation, culture, and diversity, continues to captivate the world with its unique charm and character. As a critic, I find myself both enamored and occasionally perplexed by the city's multifaceted personality.\n\nSan Francisco's architecture is a testament to its rich history and progressive spirit. The iconic cable cars, Victorian houses, and the Golden Gate Bridge are not just tourist attractions but symbols of the city's enduring appeal. However, the","tool_calls":[]},"logprobs":null,"finish_reason":"length","stop_reason":null}],"usage":{"prompt_tokens":39,"total_tokens":139,"completion_tokens":100,"prompt_tokens_details":null},"prompt_logprobs":null}
  5. ゲートウェイがポート 8081 の推論サービス拡張機能を介して推論サービスにルーティングされていることを確認します。

    curl -X POST ${GATEWAY_HOST}:8081/v1/chat/completions -H 'Content-Type: application/json' -d '{
        "model": "/model/qwen",
        "max_completion_tokens": 100,
        "temperature": 0,
        "messages": [
          {
            "role": "user",
            "content": "Write as if you were a critic: Los Angeles"
          }
        ]
    }'

    期待される出力:

    {"id":"chatcmpl-cc4fcd0a-6a66-4684-8dc9-284d4eb77bb7","object":"chat.completion","created":1747191969,"model":"/model/qwen","choices":[{"index":0,"message":{"role":"assistant","reasoning_content":null,"content":"Los Angeles, the sprawling metropolis often referred to as \"L.A.,\" is a city that defies easy description. It is a place where dreams are made and broken, where the sun never sets, and where the line between reality and fantasy is as blurred as the smog that often hangs over its valleys. As a critic, I find myself both captivated and perplexed by this city that is as much a state of mind as it is a physical place.\n\nOn one hand, Los","tool_calls":[]},"logprobs":null,"finish_reason":"length","stop_reason":null}],"usage":{"prompt_tokens":39,"total_tokens":139,"completion_tokens":100,"prompt_tokens_details":null},"prompt_logprobs":null}

(オプション) ステップ 5: LLM サービスの可観測性メトリクスとダッシュボードを構成する

説明

クラスターで Managed Service for Prometheus を有効にして使用する必要があります。これには追加料金が発生する場合があります。

  1. Prometheus インスタンスの デフォルトのサービスディスカバリー メカニズムを使用してメトリクスを収集するために、vLLM サービスポッドに Prometheus メトリクス収集アノテーションを追加できます。これにより、vLLM サービスの内部状態を監視します。

    ...
    annotations:
      prometheus.io/path: /metrics // メトリクスの公開先 HTTP パス
      prometheus.io/port: "8000" // メトリクスの公開ポート。vLLM サーバーのリスニングポート
      prometheus.io/scrape: "true" // 現在のポッドのメトリクスをスクレイプするかどうかを指定します
    ...

    次の表に、vLLM サービスによって提供されるいくつかの監視メトリクスを示します。

    メトリック

    説明

    vllm:gpu_cache_usage_perc

    vLLM による GPU キャッシュの使用率。 vLLM が起動すると、KV キャッシュのためにできるだけ多くの GPU ビデオメモリを事前に占有します。 vLLM サーバーの場合、使用率が低いほど、GPU が新しいリクエストにリソースを割り当てるためのスペースが増えます。

    vllm:request_queue_time_seconds_sum

    待機状態でキューに費やされた時間。 LLM 推論リクエストが vLLM サーバーに到着した後、すぐに処理されない場合があり、vLLM スケジューラがプリフィルとデコードをスケジュールするのを待つ必要があります。

    vllm:num_requests_running

    vllm:num_requests_waiting

    vllm:num_requests_swapped

    推論を実行中、待機中、メモリにスワップされたリクエストの数。これは、vLLM サービスの現在のリクエスト負荷を評価するために使用できます。

    vllm:avg_generation_throughput_toks_per_s

    vllm:avg_prompt_throughput_toks_per_s

    プリフィルステージで消費されたトークン数/秒と、デコードステージで生成されたトークン数/秒。

    vllm:time_to_first_token_seconds_bucket

    リクエストが vLLM サービスに送信されてから最初のトークンが応答されるまでのレイテンシレベル。このメトリックは通常、リクエストコンテンツを出力してからクライアントが最初の応答を受信するまでにかかる時間を表し、LLM ユーザーエクスペリエンスに影響を与える重要なメトリックです。

    これらのメトリクスに基づいて、特定のアラートルールを設定して、LLM サービスパフォーマンスのリアルタイム監視と異常検出を有効にできます。

  2. LLM 推論サービスのリアルタイム監視用に Grafana ダッシュボードを構成します。 Grafana ダッシュボードを使用して、vLLM に基づいてデプロイされた LLM 推論サービスを観察できます。

    • LLM サービスのリクエストレートと合計トークンスループットを監視する。

    • 推論ワークロードの内部状態を監視する。

    Grafana のデータソースとして機能する Prometheus インスタンスが vLLM の監視メトリクスを収集していることを確認します。 LLM 推論サービスの可観測ダッシュボードを作成するには、次のコンテンツを Grafana にインポート します。

    image

    JSON を表示

    {
      "annotations": {
        "list": [
          {
            "builtIn": 1,
            "datasource": {
              "type": "grafana",
              "uid": "-- Grafana --"
            },
            "enable": true,
            "hide": true,
            "iconColor": "rgba(0, 211, 255, 1)",
            "name": "アノテーションとアラート", // 翻訳済
            "target": {
              "limit": 100,
              "matchAny": false,
              "tags": [],
              "type": "dashboard"
            },
            "type": "dashboard"
          }
        ]
      },
      "description": "vLLM 推論サーバーの監視", // 翻訳済
      "editable": true,
      "fiscalYearStartMonth": 0,
      "graphTooltip": 0,
      "id": 1,
      "links": [],
      "liveNow": false,
      "panels": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "description": "エンドツーエンドのリクエストレイテンシ(秒単位)。", // 翻訳済
          "fieldConfig": {
            "defaults": {
              "color": {
                "mode": "palette-classic"
              },
              "custom": {
                "axisBorderShow": false,
                "axisCenteredZero": false,
                "axisColorMode": "text",
                "axisLabel": "",
                "axisPlacement": "auto",
                "barAlignment": 0,
                "barWidthFactor": 0.6,
                "drawStyle": "line",
                "fillOpacity": 0,
                "gradientMode": "none",
                "hideFrom": {
                  "legend": false,
                  "tooltip": false,
                  "viz": false
                },
                "lineInterpolation": "linear",
                "lineWidth": 1,
                "pointSize": 5,
                "scaleDistribution": {
                  "type": "linear"
                },
                "showPoints": "auto",
                "spanNulls": false,
                "stacking": {
                  "group": "A",
                  "mode": "none"
                },
                "thresholdsStyle": {
                  "mode": "off"
                }
              },
              "mappings": [],
              "thresholds": {
                "mode": "absolute",
                "steps": [
                  {
                    "color": "green",
                    "value": null
                  },
                  {
                    "color": "red",
                    "value": 80
                  }
                ]
              },
              "unit": "s"
            },
            "overrides": []
          },
          "gridPos": {
            "h": 9,
            "w": 12,
            "x": 0,
            "y": 0
          },
          "id": 2,
          "options": {
            "legend": {
              "calcs": [],
              "displayMode": "list",
              "placement": "bottom"
            },
            "tooltip": {
              "mode": "single",
              "sort": "none"
            }
          },
          "targets": [
            {
              "datasource": {
                "type": "prometheus",
                "uid": "${DS_PROMETHEUS}"
              },
              "exemplar": true,
              "expr": "histogram_quantile(0.9, sum(rate(vllm_request_latency_seconds_bucket[1m])) by (le))",
              "interval": "",
              "legendFormat": "p90",
              "refId": "A"
            },
            {
              "datasource": {
                "type": "prometheus",
                "uid": "${DS_PROMETHEUS}"
              },
              "exemplar": true,
              "expr": "histogram_quantile(0.5, sum(rate(vllm_request_latency_seconds_bucket[1m])) by (le))",
              "hide": false,
              "interval": "",
              "legendFormat": "p50",
              "refId": "B"
            }
          ],
          "title": "リクエストレイテンシ p90/p50", // 翻訳済
          "type": "timeseries"
        },
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "description": "1 秒あたりのトークンのスループット。", // 翻訳済
          "fieldConfig": {
            "defaults": {
              "color": {
                "mode": "palette-classic"
              },
              "custom": {
                "axisCenteredZero": false,
                "axisColorMode": "text",
                "axisLabel": "",
                "axisPlacement": "auto",
                "barAlignment": 0,
                "drawStyle": "line",
                "fillOpacity": 0,
                "gradientMode": "none",
                "hideFrom": {
                  "legend": false,
                  "tooltip": false,
                  "viz": false
                },
                "lineInterpolation": "linear",
                "lineWidth": 1,
                "pointSize": 5,
                "scaleDistribution": {
                  "type": "linear"
                },
                "showPoints": "auto",
                "spanNulls": false,
                "stacking": {
                  "group": "A",
                  "mode": "none"
                },
                "thresholdsStyle": {
                  "mode": "off"
                }
              },
              "mappings": [],
              "thresholds": {
                "mode": "absolute",
                "steps": [
                  {
                    "color": "green",
                    "value": null
                  },
                  {
                    "color": "red",
                    "value": 80
                  }
                ]
              }
            },
            "overrides": []
          },
          "gridPos": {
            "h": 8,
            "w": 12,
            "x": 0,
            "y": 9
          },
          "id": 4,
          "options": {
            "legend": {
              "calcs": [],
              "displayMode": "list",
              "placement": "bottom"
            },
            "tooltip": {
              "mode": "single",
              "sort": "none"
            }
          },
          "targets": [
            {
              "datasource": {
                "type": "prometheus",
                "uid": "${DS_PROMETHEUS}"
              },
              "exemplar": true,
              "expr": "sum(rate(vllm_avg_generation_throughput_toks_per_s[1m]))",
              "interval": "",
              "legendFormat": "生成スループット", // 翻訳済
              "refId": "A"
            },
            {
              "datasource": {
                "type": "prometheus",
                "uid": "${DS_PROMETHEUS}"
              },
              "exemplar": true,
              "expr": "sum(rate(vllm_avg_prompt_throughput_toks_per_s[1m]))",
              "interval": "",
              "legendFormat": "プロンプトスループット", // 翻訳済
              "refId": "B"
            }
          ],
          "title": "トークンスループット", // 翻訳済
          "type": "timeseries"
        },
            {
              "datasource": {
                "type": "prometheus",
                "uid": "${DS_PROMETHEUS}"
              },
              "description": "GPU キャッシュの使用率。", // 翻訳済
              "fieldConfig": {
                "defaults": {
                  "color": {
                    "mode": "palette-classic"
                  },
                  "custom": {
                    "axisCenteredZero": false,
                    "axisColorMode": "text",
                    "axisLabel": "",
                    "axisPlacement": "auto",
                    "barAlignment": 0,
                    "drawStyle": "line",
                    "fillOpacity": 0,
                    "gradientMode": "none",
                    "hideFrom": {
                      "legend": false,
                      "tooltip": false,
                      "viz": false
                    },
                    "lineInterpolation": "linear",
                    "lineWidth": 1,
                    "pointSize": 5,
                    "scaleDistribution": {
                      "type": "linear"
                    },
                    "showPoints": "auto",
                    "spanNulls": false,
                    "stacking": {
                      "group": "A",
                      "mode": "none"
                    },
                    "thresholdsStyle": {
                      "mode": "off"
                    },
                    "unit": "percentunit"
                  },
                  "mappings": [],
                  "thresholds": {
                    "mode": "absolute",
                    "steps": [
                      {
                        "color": "green",
                        "value": null
                      },
                      {
                        "color": "red",
                        "value": 80
                      }
                    ]
                  }
                },
                "overrides": []
              },
              "gridPos": {
                "h": 9,
                "w": 12,
                "x": 12,
                "y": 0
              },
              "id": 6,
              "options": {
                "legend": {
                  "calcs": [],
                  "displayMode": "list",
                  "placement": "bottom"
                },
                "tooltip": {
                  "mode": "single",
                  "sort": "none"
                }
              },
              "targets": [
                {
                  "datasource": {
                    "type": "prometheus",
                    "uid": "${DS_PROMETHEUS}"
                  },
                  "exemplar": true,
                  "expr": "sum(vllm_gpu_cache_usage_perc)",
                  "interval": "",
                  "legendFormat": "{{instance}}",
                  "refId": "A"
                }
              ],
              "title": "GPU キャッシュ使用率", // 翻訳済
              "type": "timeseries"
            }
      ],
      "refresh": "",
      "schemaVersion": 36,
      "style": "dark",
      "tags": [],
      "templating": {
        "list": [
          {
            "current": {
              "selected": false,
              "text": "Prometheus", // 英語のまま
              "value": "${DS_PROMETHEUS}"
            },
            "datasource": {
              "type": "prometheus",
              "uid": "${DS_PROMETHEUS}"
            },
            "hide": 0,
            "includeAll": false,
            "multi": false,
            "name": "DS_PROMETHEUS",
            "options": [],
            "query": "prometheus", // 英語のまま
            "refresh": 1,
            "regex": "",
            "skipUrlSync": false,
            "type": "datasource"
          }
        ]
      },
      "time": {
        "from": "now-1h",
        "to": "now"
      },
      "timepicker": {},
      "timezone": "",
      "title": "vLLM 推論サーバー", // 翻訳済
      "uid": "kEnZ-974z",
      "version": 2,
      "weekStart": ""
    }

    ヒント: ブラウザの開発者ツールを使用して、REST API のレスポンスを確認できます。

    image

  3. ACK クラスタの場合、vllm ベンチマーク を使用して推論サービスのストレステストを実行し、標準 HTTP ルーティングと推論拡張ルーティングの負荷分散機能を比較します。

    1. ストレステスト ワークロードをデプロイします。

      kubectl apply -f- <<EOF
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        labels:
          app: vllm-benchmark
        name: vllm-benchmark
        namespace: default
      spec:
        progressDeadlineSeconds: 600
        replicas: 1
        revisionHistoryLimit: 10
        selector:
          matchLabels:
            app: vllm-benchmark
        strategy:
          rollingUpdate:
            maxSurge: 25%
            maxUnavailable: 25%
          type: RollingUpdate
        template:
          metadata:
            creationTimestamp: null
            labels:
              app: vllm-benchmark
          spec:
            containers:
            - command:
              - sh
              - -c
              - sleep inf
              image: registry-cn-hangzhou.ack.aliyuncs.com/dev/llm-benchmark:random-and-qa
              imagePullPolicy: IfNotPresent
              name: vllm-benchmark
              resources: {}
              terminationMessagePath: /dev/termination-log
              terminationMessagePolicy: File
            dnsPolicy: ClusterFirst
            restartPolicy: Always
            schedulerName: default-scheduler
            securityContext: {}
            terminationGracePeriodSeconds: 30
      EOF
    2. ストレステストを開始します。

      1. ゲートウェイの内部 IP アドレスを取得します。

        export GW_IP=$(kubectl get svc -n envoy-gateway-system -l gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=qwen-inference-gateway -o jsonpath='{.items[0].spec.clusterIP}')
      2. ストレステストを実行します。

        標準 HTTP ルーティング

        kubectl exec -it deploy/vllm-benchmark -- env GW_IP=${GW_IP} python3 /root/vllm/benchmarks/benchmark_serving.py \
        --backend vllm \
        --model /models/DeepSeek-R1-Distill-Qwen-7B \
        --served-model-name /model/qwen \
        --trust-remote-code \
        --dataset-name random \
        --random-prefix-len 10 \
        --random-input-len 1550 \
        --random-output-len 1800 \
        --random-range-ratio 0.2 \
        --num-prompts 3000 \
        --max-concurrency 200 \
        --host $GW_IP \
        --port 8080 \
        --endpoint /v1/completions \
        --save-result \
        2>&1 | tee benchmark_serving.txt

        推論サービス ルーティング

        kubectl exec -it deploy/vllm-benchmark -- env GW_IP=${GW_IP} python3 /root/vllm/benchmarks/benchmark_serving.py \
        --backend vllm \
        --model /models/DeepSeek-R1-Distill-Qwen-7B \
        --served-model-name /model/qwen \
        --trust-remote-code \
        --dataset-name random \
        --random-prefix-len 10 \
        --random-input-len 1550 \
        --random-output-len 1800 \
        --random-range-ratio 0.2 \
        --num-prompts 3000 \
        --max-concurrency 200 \
        --host $GW_IP \
        --port 8081 \
        --endpoint /v1/completions \
        --save-result \
        2>&1 | tee benchmark_serving.txt

    テスト後、ダッシュボードで標準 HTTP ルーティングと推論サービス拡張のルーティング機能を比較できます。

    49c8528de7c25b87093795a1bac152fc

    ご覧のとおり、HTTP ルートを使用するワークロードのキャッシュ使用率分布は不均一ですが、LLM ルートを使用するワークロードのキャッシュ使用率分布は正常です。

次のステップ

推論拡張機能付きゲートウェイは、さまざまな推論シナリオの要件を満たすために、さまざまな負荷分散ポリシーを提供します。InferencePool 内のポッドの負荷分散ポリシーを構成するには、inference.networking.x-k8s.io/routing-strategy アノテーションを InferencePool の構成に追加します。

次のサンプル YAML テンプレートは、app: vllm-app セレクターを使用して推論サービスポッドを選択し、推論サーバーのメトリックに基づいて動作するデフォルトの負荷分散ポリシーを使用します。

apiVersion: inference.networking.x-k8s.io/v1alpha2
kind: InferencePool
metadata:
  name: vllm-app-pool
  annotations:
    inference.networking.x-k8s.io/routing-strategy: "DEFAULT"
spec:
  targetPortNumber: 8000
  selector:
    app: vllm-app
  extensionRef:
    name: inference-gateway-ext-proc

次の表に、推論拡張機能付き ACK ゲートウェイによって提供される負荷分散ポリシーを示します。

ポリシー

説明

DEFAULT

推論サービスのメトリックに基づいて動作するデフォルトの負荷分散ポリシー。このポリシーは、多次元メトリックに基づいて推論サーバーのステータスを評価し、評価されたステータスに基づいて負荷分散を実行します。メトリックには、リクエストキューの長さと GPU キャッシュ使用率が含まれます。

PREFIX_CACHE

リクエストプレフィックス一致負荷分散ポリシー。このポリシーは、同じプレフィックスを持つリクエストを同じ推論サーバー上のポッドに送信しようとします。このポリシーは、同じプレフィックスを持つ大量のリクエストを受信し、推論サーバーで自動プレフィックスキャッシュ機能が有効になっているシナリオに適しています。

次のリストは、典型的なシナリオを示しています。

  • 長いドキュメントクエリ:ユーザーは、ソフトウェアユーザーガイドや年次レポートなど、同じ長いドキュメントをクエリするためにさまざまなメソッドを頻繁に使用します。

  • 複数ターンの会話:ユーザーは、同じ会話でアプリケーションプログラムと複数回対話します。