Skip to main content
Featured image for Keda e as filas do Kafka

Keda e as filas do Kafka

·838 words·4 mins

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:

  1. Os gatilhos definidos no ScaledObject são ativados
  2. As regras configuradas são processadas pelo KEDA Controller
  3. O Metrics Adapter fornece as métricas externas ao HPA
  4. O HPA decide aumentar ou diminuir o número de réplicas
  5. 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.yaml para ajustar tolerations, affinity e 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:

  1. Produtor de mensagens: responsável por enviar mensagens para um tópico Kafka.
  2. 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.0 Consumidor: 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"
configmap.png

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
produtor.png

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"

consumer.png

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"
scaledobject.png

Teste de estresse
#

Vemos na imagem abaixo que o lag ainda não atingiu o valor que definimos.

1-replica.png

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

lag.png

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

scaling.png

Apoś uns 2 minutos de lag, o maximo de replicas já é atingido para consumir as mensagens.

maxreplica.png

Uma vez consumida todas as mensagens.

lag_consumido.png

As replicas vão baixando:

scalingdown.png

E por fim volta ao minimo de replicas:

min_replica.png

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 maxReplicaCount deve 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