【ITニュース解説】Kubernetes Autoscaling with KEDA: Event-Driven Scaling for Queues and Microservices - Part 1
2025年09月20日に「Dev.to」が公開したITニュース「Kubernetes Autoscaling with KEDA: Event-Driven Scaling for Queues and Microservices - Part 1」について初心者にもわかりやすく解説しています。
ITニュース概要
KEDAは、KubernetesでKafkaやRabbitMQのキューなど「イベント」に基づきPodを自動増減させる仕組み。CPUやメモリだけでなく、キューのメッセージ数で負荷に応じてスケーリングし、コンシューマーの過負荷や不足を防ぐ。これにより、処理の遅延やリソースの無駄を解消し、システムを効率化する。複雑な構成には工夫が必要となる場合がある。
ITニュース解説
Kubernetes環境でメッセージキューシステム、例えばKafkaやRabbitMQといったものを使っていると、一つ課題に直面することがある。それは、メッセージを処理するアプリケーション(コンシューマーと呼ぶ)のスケール調整が難しいという問題だ。Kubernetesの標準機能であるHorizontal Pod Autoscaler(HPA)は、CPU使用率やメモリ使用量に基づいてPodの数を増減させるが、メッセージキューの処理では、必ずしもCPU使用率と実際の仕事量が一致しない。メッセージが大量にたまっているにも関わらずCPU使用率が低い場合、コンシューマーのPodが少なく、処理が滞ってしまうことがある。逆に、メッセージがほとんどないのに多くのPodが起動していると、リソースが無駄になってしまう。このような状況は、システムの応答性を悪化させたり、コストを無駄にしたりする原因となる。
この問題を解決するために登場したのがKEDA(Kubernetes-based Event-Driven Autoscaling)である。KEDAは、Kubernetesのワークロードを外部のイベントやメトリクスに基づいて自動的にスケールさせるための軽量なツールだ。HPAがCPUやメモリといったリソースの利用状況を見るのに対し、KEDAはキューにたまっているメッセージの数やPrometheusからのメトリクス、さらにはクラウドサービスからのイベントなど、よりビジネスロジックに近い指標を見てPodの数を調整できる点が特徴である。KEDA自体もKubernetesクラスター内でDeploymentとして動作する。特別な設定は不要で、他のアプリケーションと同様にCPUやメモリを消費する。多数の監視対象やトリガーを定義すると、KEDA自身のPodもそれに応じてリソースを多く使うようになるため、その点には注意が必要だ。
KEDAがどのように機能するかというと、主にScaledObjectという新しいKubernetesオブジェクトを導入することで実現する。このScaledObjectは、どのワークロード(Deployment)をスケールさせるかをKEDAに指示するための設定ファイルのようなものだ。各ScaledObjectには、一つまたは複数のトリガーを設定できる。トリガーとは、KEDAが監視するイベントやメトリクスの種類と、スケーリングを開始するための閾値のことである。もし複数のトリガーが設定された場合、KEDAはそれらのトリガーのいずれか一つでも閾値を超えた場合にPodをスケールさせる「OR」ロジックで動作する。重要な点として、一つのScaledObjectで定義されたトリガーは、対象となるDeployment内の全てのPodに適用されるため、Deployment内の一部のPodだけを独立してスケールさせることはできない。
具体的なScaledObjectの例として、RabbitMQのキューの長さに応じてコンシューマーをスケールさせるケースを考えてみよう。設定ファイルでは、apiVersion: keda.sh/v1alpha1、kind: ScaledObjectとしてKEDAのリソースであることを示す。metadata.nameにはorders-consumer-scalerのようなわかりやすい名前をつける。spec.scaleTargetRef.nameには、スケールさせたいDeploymentの名前、例えばorders-consumerを指定する。そして、minReplicaCountでPodの最小数を1、maxReplicaCountでPodの最大数を10と設定する。トリガーの部分では、type: rabbitmqとしてRabbitMQを監視対象と指定し、metadataセクションで監視するqueueName(例: orders-queue)やRabbitMQへの接続情報(host)、そして重要なqueueLengthという閾値を設定する。この例では"100"と設定されており、orders-queueにメッセージが100個以上たまると、orders-consumer DeploymentのPod数がスケールアップの対象となる。
KEDAは、このqueueLengthという閾値と現在のキューのメッセージ数を比較して、必要なPod数を計算する。例えば、閾値が100個で、現在のキューのメッセージ数が50個であれば、最小Pod数である1を維持する。メッセージが120個に増えれば、必要なPod数はceil(120 / 100) = 2と計算され、Pod数は2に増える。さらに250個に増えればceil(250 / 100) = 3で3つのPodに増える。ただし、この計算で最大Pod数を超えた場合は、maxReplicaCountで設定した最大値に制限される。KEDAはこの計算結果に基づいて、内部的にHPAリソースを更新し、それを通じて対象のDeploymentのPod数を自動的に調整する。これにより、メッセージが大量にたまってもシステムが迅速に対応できるようになる。
しかし、KEDAにもいくつかの制限がある。最も顕著なのは、一つのScaledObjectで複数の異なるキューと、それぞれに対応する異なるコンシューマーDeploymentを管理できない点だ。例えば、10個の異なる処理ロジックを持つキューが存在し、それぞれが異なるコンシューマーDeploymentによって処理される必要がある場合、KEDAの標準機能では、各キューとコンシューマーのペアに対して個別のScaledObjectを作成する必要がある。また、前述の通り、複数のトリガーを設定した場合のスケーリングロジックは「OR」であるため、例えば同じDeploymentが二つの異なるキューを処理していて、片方のキューにのみ大量のメッセージがたまった場合でも、全てのPodが一緒にスケールしてしまう。これは、マイクロサービスアーキテクチャで複数のキューと複雑なワークフローを持つシステムにはあまり適していない。それぞれのサービスが独立してスケールすべき場面で、一括でしかスケールできないため、リソースの効率性が落ちる可能性がある。
さらに、KEDA自体がDeploymentとして動作するため、多数のScaledObjectやトリガーを定義すると、KEDA自身のCPUやメモリ使用量が増加する。これにより、Kubernetesクラスター全体のリソース消費量が増え、管理が複雑になる可能性も存在する。kubectl get scaledobjectsコマンドで現在のScaledObjectの一覧を確認すると、各ScaledObjectが一つのDeploymentを対象としていることがわかる。例えば、orders-consumer-scalerがorders-consumer Deploymentを、payments-consumer-scalerがpayments-consumer Deploymentを対象としているように、個別の管理が必要となる。
結論として、KEDAはメッセージキューの長さのようなイベントに基づいてKubernetesワークロードを自動的にスケールさせる強力なツールであり、シンプルで単一のキューを持つアプリケーションには非常に有効である。しかし、一つのScaledObjectがターゲットとするのは一つのDeploymentのみであり、複数のトリガーが設定された場合のスケーリングロジックがORであるため、複数のキューを異なるロジックで処理する複雑なマイクロサービスには、そのままでは適用しにくい場面がある。その場合、複数のDeploymentとScaledObjectを組み合わせるか、KEDAの機能だけでは対応できないより複雑なスケーリングロジックが必要な場合は、カスタムのオートスケーラーを検討する必要があるだろう。まずはKEDAから始めて、必要に応じてより高度なソリューションに移行するのが賢明なアプローチである。