大規模言語モデル (LLM) 推論のための Prefill-Decode (PD) デカップリングアーキテクチャでは、Prefill ステージと Decode ステージのリソース要件が大幅に異なります。CPU や GPU 使用率などの従来のメトリックは、自動スケーリングには効果がありません。このトピックでは、Dynamo フレームワークを例として使用し、Kubernetes Event-driven Autoscaling (KEDA) を使用して、NATS メッセージキュー内のメッセージバックログに基づいて Prefill ロールに独立した自動スケーリングポリシーを設定する方法を説明します。このメソッドにより、オンデマンドのリソース割り当てが可能になり、サービスコストとパフォーマンスが最適化されます。
前提条件
Dynamo PD デカップリング推論サービスをデプロイしていること。
Alibaba Cloud Prometheus モニタリングコンポーネントをデプロイしていること。詳細については、「Alibaba Cloud Prometheus を使用したモニタリング」をご参照ください。
ack-keda コンポーネントをデプロイしていること。詳細については、「ack-keda のデプロイ」をご参照ください。
制限事項
このトピックの自動スケーリングソリューションは、PD デカップリングアーキテクチャの Prefill ロールにのみ適用されます。Decode ロールには、別の自動スケーリングポリシーが必要です。Decode ロールには GPU メモリ使用率を使用することをお勧めします。
このトピックの例は、Dynamo 推論フレームワークに基づいています。別のフレームワークを使用する場合は、NATS Stream 名や Consumer 名など、関連する構成を適宜調整する必要があります。
手順
RoleBasedGroup (RBG) は、PD デカップリングされた推論サービス内の各ロールの独立したスケーリングを可能にします。このトピックでは、Dynamo PD デカップリングフレームワークを例として、Kubernetes Event-driven Autoscaling (KEDA) を使用して Prefill ロールの個別の自動スケーリングポリシーを設定する方法について説明します。
Dynamo PD デカップリングアーキテクチャでは、保留中の推論リクエストはメッセージとして NATS メッセージキューの dynamo_prefill_queue ストリームにプッシュされます。Prefill インスタンスはコンシューマーとして機能し、このキューからメッセージをプルして処理します。キュー内の保留中のメッセージ数は、Prefill ロールのワークロードを正確に反映します。KEDA が提供する NATS JetStream Scaler は、このキューのメッセージバックログをモニターします。その後、自動スケーリングをトリガーして Prefill インスタンスの数を調整します。
この自動スケーリングポリシーを本番環境に適用する前に、テスト環境で徹底的なストレステストを実行してください。これにより、ワークロードに最適なlagThreshold(メッセージバックログのしきい値) とpollingIntervalを決定できます。不適切な構成は、サービスパフォーマンスに影響を与えるスケールアウトの遅延や、リソースを浪費する過剰なスケールアウトを引き起こす可能性があります。
ステップ 1: RBG ロールの ScalingAdapter を作成する
KEDA が RBG 内の特定のロールのレプリカ数を独立して制御できるようにするには、RBG の作成時にターゲットロールの ScalingAdapter を有効にします。この操作により、RoleBasedGroupScalingAdapter リソースが自動的に作成され、ロールにバインドされます。
rbg.yamlファイルを作成し、73-74 行目でscalingAdapter: enable: trueを設定して、RBG の `prefill` ロールの ScalingAdapter を有効にすることができます。次のコマンドを実行してリソースを作成できます。
kubectl apply -f ./rbg.yamlRBG を作成すると、システムは ScalingAdapter が有効になっているロールに対して RoleBasedGroupScalingAdapter カスタムリソースを自動的に作成します。その後、システムはこのリソースをロールにバインドします。RoleBasedGroupScalingAdapter は、バインドされたロールの Scale サブリソース実装を提供します。
次のコマンドを実行して、指定されたロールに対して自動的に作成された
RoleBasedGroupScalingAdapterを表示できます。kubectl get rolebasedgroupscalingadapter出力例:
NAME PHASE REPLICAS dynamo-pd-prefill Bound 2次のコマンドを実行して、
dynamo-pd-prefillScalingAdapter のステータスを確認できます。kubectl describe rolebasedgroupscalingadapter dynamo-pd-prefill出力例では、
Status.PhaseはBoundである必要があります。これは、ScalingAdapter が RBG の prefill ロールに正常にバインドされたことを示します。Name: dynamo-pd-prefill Namespace: default Labels: <none> Annotations: <none> API Version: workloads.x-k8s.io/v1alpha1 Kind: RoleBasedGroupScalingAdapter Metadata: Creation Timestamp: 2025-07-25T06:10:37Z Generation: 2 Owner References: API Version: workloads.x-k8s.io/v1alpha1 Block Owner Deletion: true Kind: RoleBasedGroup Name: dynamo-pd UID: 5dd61668-79f3-4197-a5db-b778ce460270 Resource Version: 1157485 UID: edbb8373-2b9c-4ad1-8b6b-d5dfff71e769 Spec: Replicas: 2 Scale Target Ref: Name: dynamo-pd Role: prefill Status: Phase: Bound Replicas: 2 Selector: rolebasedgroup.workloads.x-k8s.io/name=dynamo-pd,rolebasedgroup.workloads.x-k8s.io/role=prefill Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulBound 25s RoleBasedGroupScalingAdapter rbg [dynamo-pd] のスケールターゲットロール [prefill] の検出に成功しました
ステップ 2: メッセージキューをモニターする KEDA ScaledObject を作成する
ScaledObject リソースを作成し、スケーリングルールを定義して、前のステップで作成した RoleBasedGroupScalingAdapter に関連付けることができます。
次の内容で
scaledobject.yamlファイルを作成できます。この構成では、dynamo-pd-prefillScalingAdapter をスケールターゲットとして指定し、NATS メッセージキューのバックログに基づいてトリガーを設定します。以下のスケーリングポリシーのパラメーター設定は、デモ目的のみです。ビジネスシナリオに基づいて構成を調整する必要があります。
apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: dynamo-prefill-scaledobject spec: pollingInterval: 30 # デモ目的。デフォルト: 30 秒。 minReplicaCount: 1 # デモ目的。デフォルト: 0。 maxReplicaCount: 6 # デモ目的。デフォルト: 100。 scaleTargetRef: apiVersion: workloads.x-k8s.io/v1alpha1 kind: RoleBasedGroupScalingAdapter name: dynamo-pd-prefill # RoleBasedGroup の Prefill ロールをスケールターゲットとして指定します。 triggers: - type: nats-jetstream metadata: natsServerMonitoringEndpoint: "nats.default.svc.cluster.local:8222" # NATS サービスエンドポイント。 account: "$G" # Nats アカウントが設定されていない場合のデフォルト値。 stream: "dynamo_prefill_queue" # Dynamo の PrefillQueue の名前。 consumer: "worker-group" # Dynamo のコンシューマーの永続化名。 lagThreshold: "5" # 指定された Nats キュー内の保留メッセージ数に対するスケーリングのしきい値。 useHttps: "false" # HTTPS プロトコルを使用するかどうかを指定します。次のコマンドを実行してリソースを作成できます。
kubectl apply -f ./scaledobject.yaml次のコマンドを実行して、KEDA
ScaledObjectリソースのステータスを確認できます。kubectl describe so dynamo-prefill-scaledobjectサンプル出力では、
Status.ConditionsのReadyステータスがTrueと表示されます。KEDA は Horizontal Pod Autoscaler (HPA) リソースも自動的に作成します。HPA 名は
Status.HpaNameフィールドに記録されます。次のコマンドを実行して HPA を表示できます。kubectl get hpa keda-hpa-dynamo-prefill-scaledobject
ステップ 3: (オプション) ストレステストとスケーリング効果の検証
ストレステスト用のサービスインスタンスを作成し、ベンチマークツールを使用してサービスをテストできます。
ベンチマークツールとその使用方法の詳細については、「vLLM Benchmark」をご参照ください。
benchmark.yamlファイルを作成できます。次のコマンドを実行して、ストレステスト用のサービスインスタンスを作成できます。
kubectl create -f benchmark.yamlインスタンスが実行されたら、インスタンスで次のコマンドを実行してストレステストを実行できます。
python3 $VLLM_ROOT_DIR/benchmarks/benchmark_serving.py \ --backend openai-chat \ --model /models/Qwen3-32B/ \ --served-model-name qwen \ --trust-remote-code \ --dataset-name random \ --random-input-len 1500 \ --random-output-len 100 \ --num-prompts 320 \ --max-concurrency 32 \ --host dynamo-service \ --port 8000 \ --endpoint /v1/chat/completions
ストレステスト中に、新しいターミナルを開いて次のコマンドを実行し、HPA スケーリングイベントを監視できます。
kubectl describe hpa keda-hpa-dynamo-prefill-scaledobject出力例では、
EventsフィールドにSuccessfulRescaleイベントが記録されています。これは、KEDA が NATS キューのバックログに基づいてスケールアウトを正常にトリガーしたことを示します。Name: keda-hpa-dynamo-prefill-scaledobject Namespace: default Reference: RoleBasedGroupScalingAdapter/dynamo-pd-prefill Min replicas: 1 Max replicas: 6 RoleBasedGroupScalingAdapter pods: 6 current / 6 desired Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 2m1s horizontal-pod-autoscaler 新しいサイズ: 4; 理由: 外部メトリック s0-nats-jetstream-dynamo_prefill_queue(&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name: dynamo-prefill-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},}) がターゲットを超えました Normal SuccessfulRescale 106s horizontal-pod-autoscaler 新しいサイズ: 6; 理由: 外部メトリック s0-nats-jetstream-dynamo_prefill_queue(&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name: dynamo-prefill-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},}) がターゲットを超えました同時に、
RoleBasedGroupScalingAdapterのレプリカ数の変化を監視できます。kubectl describe rolebasedgroupscalingadapter dynamo-pd-prefill出力例では、
Spec.ReplicasとStatus.Replicasの値が初期値からスケールアウトされた値 (たとえば 6) に増加します。Name: dynamo-pd-prefill Namespace: default API Version: workloads.x-k8s.io/v1alpha1 Kind: RoleBasedGroupScalingAdapter Metadata: Owner References: API Version: workloads.x-k8s.io/v1alpha1 Block Owner Deletion: true Kind: RoleBasedGroup Name: dynamo-pd Spec: Replicas: 6 Scale Target Ref: Name: dynamo-pd Role: prefill Status: Last Scale Time: 2025-08-04T02:08:10Z Phase: Bound Replicas: 6 Selector: rolebasedgroup.workloads.x-k8s.io/name=dynamo-pd,rolebasedgroup.workloads.x-k8s.io/role=prefill Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulBound 6m9s RoleBasedGroupScalingAdapter rbg [dynamo-pd] のスケールターゲットロール [prefill] の検出に成功しました Normal SuccessfulScale 4m40s RoleBasedGroupScalingAdapter rbg [dynamo-pd] のスケールターゲットロール [prefill] のレプリカを 1 から 4 にスケールすることに成功しました Normal SuccessfulScale 4m25s RoleBasedGroupScalingAdapter rbg [dynamo-pd] のスケールターゲットロール [prefill] のレプリカを 4 から 6 にスケールすることに成功しました