KEDA autoscaling baseado nas filas do Kafka#
O que é o KEDA e o que ele faz?#
O KEDA (Kubernetes Event-Driven Autoscaling) é uma ferramenta desenvolvida para ajudar no escalonamento automático de réplicas de containers com base em eventos reais.
Ele permite aumentar ou diminuir as réplicas da aplicação com base, por exemplo, na quantidade de mensagens recebidas em uma fila Kafka ou RabbitMQ, ou ainda em um alto número de requisições HTTP.
Esse modelo de autoscaling é mais eficiente do que o tradicional baseado apenas em CPU ou memória, pois reflete melhor a carga real da aplicação.
Quais são as principais peças do KEDA?#
KEDA Operator#
Responsável por consultar as fontes de dados externas e alterar automaticamente o número de réplicas das aplicações.
KEDA Metrics Server#
É o componente que fornece ao HPA (Horizontal Pod Autoscaler) métricas adicionais para a tomada de decisão sobre o autoscaling.
KEDA Scalers#
Traduzem métricas externas (Kafka, RabbitMQ, Prometheus, etc.) em valores numéricos que o HPA consegue utilizar.
CRDs (Custom Resource Definitions)#
Armazenam os parâmetros que definem quando o autoscaling deve começar.
- ScaledObject
Define os gatilhos (triggers) e as regras que indicam quando o processo de autoscaling deve ser iniciado.
Como funciona o fluxo de autoscaling do KEDA?#
Quando existe um aumento de mensagens em uma fila Kafka, o fluxo ocorre da seguinte forma:
- Os gatilhos definidos no
ScaledObjectsão ativados - As regras configuradas são processadas pelo KEDA Controller
- O Metrics Adapter fornece as métricas externas ao HPA
- O HPA decide aumentar ou diminuir o número de réplicas
- O Admission Webhook valida a configuração aplicada, evitando erros
Instalação do KEDA com Helm#
A instalação do KEDA pode ser feita de forma simples utilizando o Helm.
Obs: foi realizado o export do arquivo
values.yamlpara ajustartolerations,affinitye configurações adicionais.
kubectl create namespace keda
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm show values kedacore/keda > values.yaml
helm install -n keda keda kedacore/keda -f values.yaml
Arquitetura do exemplo#
Para este exemplo, criamos dois microsserviços simples, executando no mesmo namespace:
- Produtor de mensagens: responsável por enviar mensagens para um tópico Kafka.
- Consumidor de mensagens: responsável por consumir as mensagens e que será escalado automaticamente pelo KEDA.
Obs: Caso queira realizar um teste utilizando as imagens docker que construimos:
Produtor: gole/kafka-producer-keda:1.0Consumidor: gole/kafka-consumer-keda:1.0
Serviço produtor de mensagens (Kafka Producer)#
ConfigMap
Obs: como estamos utilizando o mesmo namespace para os dois serviços, usamos o mesmo ConfigMap.
apiVersion: v1
kind: ConfigMap
metadata:
name: kafka-config
data:
KAFKA_BOOTSTRAP_SERVERS: "kafka:9092"
KAFKA_TOPIC: "demo-topic"
MESSAGE_INTERVAL_SECONDS: "10"
MESSAGE_BATCH_SIZE: "100"

Deployment do Producer
apiVersion: apps/v1
kind: Deployment
metadata:
name: kafka-producer
spec:
replicas: 1
selector:
matchLabels:
app: kafka-producer
template:
metadata:
labels:
app: kafka-producer
spec:
containers:
- name: producer
image: gole/kafka-producer-keda:1.0
envFrom:
- configMapRef:
name: kafka-config

Serviço consumidor de mensagens (Kafka Consumer)#
Deployment do Consumer
apiVersion: apps/v1
kind: Deployment
metadata:
name: kafka-consumer
spec:
replicas: 1
selector:
matchLabels:
app: kafka-consumer
template:
metadata:
labels:
app: kafka-consumer
spec:
containers:
- name: consumer
image: gole/kafka-consumer-keda:1.0
envFrom:
- configMapRef:
name: kafka-config
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"

ScaledObject para autoscaling com Kafka
Obs: O valor de maxReplicaCount deve ser igual ou inferior à quantidade de partições do tópico Kafka. Outro ponto é que nós estamos configurando este exemplo sem autenticação.
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: kafka-scaledobject
namespace: default
labels:
deploymentName: kafka-consumer
spec:
scaleTargetRef:
name: kafka-consumer
pollingInterval: 5
minReplicaCount: 1
maxReplicaCount: 10
triggers:
- type: kafka
metadata:
consumerGroup: demo-consumer-group
bootstrapServers: kafka:9092
topic: demo-topic
lagThreshold: "1000"
offsetResetPolicy: "latest"
authMode: "none"

Teste de estresse#
Vemos na imagem abaixo que o lag ainda não atingiu o valor que definimos.

E para validar se o autoscaling está funcionando, ajustamos as variáveis no ConfigMap para os seguintes valores:
MESSAGE_INTERVAL_SECONDS: "2"
MESSAGE_BATCH_SIZE: "10000"
Isso significa que, a cada 2 segundos, o produtor enviará 10.000 mensagens para o Kafka. Esse volume irá gerar lag no consumer e, como definido no lagThreshold do ScaledObject, ao ultrapassar 1.000 mensagens pendentes, o autoscaling será acionado automaticamente

Logo após ajustarmos o configmap os lags começaram como vimos na imagem acima e o scaling começa acontecer.

Apoś uns 2 minutos de lag, o maximo de replicas já é atingido para consumir as mensagens.
Uma vez consumida todas as mensagens.
As replicas vão baixando:
E por fim volta ao minimo de replicas:
Conclusão#
Finalizamos este conteúdo mostrando como o KEDA trabalha o autoscaling de aplicações Kubernetes se baseando em eventos reais, utilizando como no exemplo o lag de um tópico Kafka como métrica principal. Com isso vemos que o autoscaling baseado em eventos se torna mais eficiente do que métricas como CPU e memória, uma vez que os eventos aumentem gradativamente sem alterar o consumo dos serviços. Autoscaling baseado em eventos é mais eficiente do que métricas tradicionais como CPU e memória
Lições aprendidas#
- O
maxReplicaCountdeve respeitar o número de partições do tópico Kafka - Após o consumo das mensagens, o KEDA realiza o scale down automaticamente
- O KEDA se integra de forma simples ao Kubernetes e ao HPA, sem complexidade adicional

