Перейти к содержимому
Hogin Hogin
Назад

KEDA: автоскейлинг по событиям и до нуля

6 мин чтения

У вас Kafka-топик, консьюмеры разгребают сообщения бэтчами, и нагрузка скачет от нуля ночью до тысяч сообщений в минуту в пиковый час. HPA по CPU в этой картине почти бесполезен: под пустой очередью консьюмер не грузит процессор, но простаивающие поды никто не остановит, а под резким всплеском метрика CPU догоняет реальность с опозданием в несколько минут. KEDA решает задачу иначе — скейлит по самому событию: глубине очереди, значению метрики, cron-расписанию — и, в отличие от HPA, умеет гасить нагрузку до нуля, когда работы нет вообще.

Содержание

Открыть содержание

Почему HPA не отвечает на вопрос «сколько воркеров нужно»

Horizontal Pod Autoscaler в Kubernetes изначально проектировался под один сценарий: веб-сервис, у которого нагрузка более-менее коррелирует с потреблением CPU или памяти. Больше запросов — больше CPU — HPA добавляет реплики. Для очередей, батчевой обработки и cron-подобных нагрузок эта корреляция ломается:

Ещё жёстче системное ограничение: HPA не умеет масштабировать Deployment до нуля реплик. Это не баг, а архитектурное решение — HPA управляет уже существующими подами и им же нужен минимум один под, чтобы вообще было что мерить. Значит, любая нагрузка «то густо, то пусто» либо держит нулевые по факту, но оплаченные реплики круглые сутки, либо скейлится вручную.

HPA видит только CPU/RAM, KEDA — глубину очереди, метрику или cron

Что KEDA делает поверх HPA

KEDA (Kubernetes Event-Driven Autoscaling) — graduated-проект CNCF, который не заменяет HPA, а достраивает его в двух направлениях сразу.

Во-первых, KEDA приносит более 60 scalers — коннекторов к источникам событий: Kafka, RabbitMQ, Prometheus, AWS SQS, PostgreSQL, cron-расписание и десятки других. Каждый scaler умеет превратить «глубину очереди» или «значение метрики» в число, понятное Kubernetes.

Во-вторых, и это ключевое отличие, KEDA решает проблему нуля. Под капотом это выглядит так: вы описываете ScaledObject — CRD, который ссылается на ваш Deployment или StatefulSet и задаёт триггеры. KEDA-оператор в ответ на это сам создаёт стандартный Kubernetes HPA, подключённый к KEDA как к External Metrics API — то есть с точки зрения Kubernetes ничего экзотического не происходит, обычный HPA просто питается метрикой, которую поставляет KEDA. Но переход между 0 и 1 репликой HPA сделать не может в принципе — этим занимается отдельная логика самого KEDA-оператора: пока реплик 0, HPA не создаётся вообще, а KEDA сам следит за источником событий и при появлении активности поднимает Deployment до 1 реплики, передавая управление дальше уже штатному HPA.

ScaledObject → KEDA создаёт HPA с внешней метрикой, а переход 0↔1 держит на себе

Для одноразовых задач вместо ScaledObject есть ScaledJob — он создаёт по Kubernetes Job на каждую единицу работы (например, на каждое сообщение в очереди) вместо того, чтобы масштабировать долгоживущий Deployment.

Сравнение

HPAKEDA
Источник метрикиCPU, память, кастомные метрики через ручной adapter60+ встроенных scalers: очереди, БД, метрики, cron
Минимум реплик1 (архитектурно не может быть 0)0 — есть отдельная логика активации
Что реально скейлитDeployment/StatefulSet напрямуюсоздаёт и обслуживает HPA + свой 0↔1 контроллер
Расписание (cron)нетвстроенный cron scaler
Кастомные метрикинужен свой Metrics/External adapterExternal Metrics API из коробки
Одноразовые задачи по событиюнетScaledJob — Job на единицу работы

Что нужно, чтобы завести автоскейлинг по Kafka

Ставим KEDA в кластер (одна установка на кластер, дальше ScaledObject заводится на каждый workload отдельно):

helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda --namespace keda --create-namespace

Дальше — ScaledObject, который скейлит Deployment консьюмера по глубине топика orders и гасит его до нуля, когда очередь пуста:

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: order-consumer
  namespace: default
spec:
  scaleTargetRef:
    name: order-consumer
  minReplicaCount: 0
  maxReplicaCount: 20
  pollingInterval: 15
  cooldownPeriod: 120
  triggers:
    - type: kafka
      metadata:
        bootstrapServers: kafka-broker:9092
        consumerGroup: order-consumer-group
        topic: orders
        lagThreshold: "50"
        activationLagThreshold: "1"
      authenticationRef:
        name: kafka-trigger-auth

Два порога здесь делают разные вещи: lagThreshold — это значение, которое KEDA передаёт в HPA как target для масштабирования от 1 до maxReplicaCount (лаг 500 при пороге 50 → HPA целится в 10 реплик). activationLagThreshold — отдельный, более чувствительный порог именно для перехода 0→1: он может быть намного меньше, чтобы консьюмер поднимался при первом же сообщении, а не ждал, пока лаг накопится до полноценного scaling-порога.

Как проверить, что скейлинг работает

KEDA не прячет свою логику — она видна как обычные Kubernetes-объекты:

# ScaledObject существует и активен
kubectl get scaledobject order-consumer -o wide

# HPA, который KEDA создал и обслуживает сама
kubectl get hpa keda-hpa-order-consumer

# статус активации и условия — почему KEDA считает источник активным/неактивным
kubectl describe scaledobject order-consumer | grep -A6 Conditions

# реплики в реальном времени под нагрузкой
kubectl get pods -l app=order-consumer -w

Хороший тест — руками закинуть пачку сообщений в топик и посмотреть, что order-consumer поднимается из нуля в течение pollingInterval, а затем, спустя cooldownPeriod после опустошения очереди, гасится обратно до нуля.

Ловушки

Итог

KEDA не переизобретает автоскейлинг — она снимает с HPA ограничение, которое было архитектурным с самого начала: невозможность смотреть на что-либо, кроме CPU/RAM, и невозможность уйти в ноль. Для стабильной веб-нагрузки HPA по-прежнему достаточно. Но там, где нагрузка определяется очередью, расписанием или внешней метрикой, а не тем, сколько процессора съедает под, — KEDA превращает scale-to-zero из ручного костыля в конфигурацию по умолчанию, а разницу видно в первом же счёте за кластер.


Поделиться:

Предыдущая статья
Renovate: автообновление зависимостей, которое не бесит
Следующая статья
OpenTofu: шифрование стейта и уход с Terraform без драмы