Desvendando o KEDA: Construindo um Scaling eficiente com Apache Kafka
Já imaginou construir um scaling eficiente baseado no processamento de mensagens em Tópicos do Apache Kafka?! Nesse artigo vamos explorar o KEDA, uma extensão do Kubernetes que permite escalar automaticamente os workloads com base em eventos.
Pré-requisitos
Como requisito fundamental para este artigo, é imprescindível utilizar o Playground desenvolvido no artigo anterior, com ele configuraremos um scaling eficiente para o consumer.
Introdução
O ecossistema Kubernetes continua a evoluir, proporcionando soluções cada vez mais avançadas para gerenciar e escalar aplicativos de maneira eficiente. Entre essas inovações, destaca-se o Kubernetes Event Driven Autoscaler (KEDA), uma ferramenta que promete revolucionar a escalabilidade de aplicações baseadas em eventos. Exploraremos a ferramenta com ênfase em seu uso para scaling consumers de tópicos do Apache Kafka.
Em vez de operarem como consumers ativos 24 horas por dia, 7 dias por semana ou possuirem quantidade de réplicas fixas, esses consumers agora podem tornar-se reativos, escalando conforme a fila de novas mensagens disponíveis para processamento.
Instalação do KEDA
Conforme mencionado anteriormente, o KEDA é uma extensão do Kubernetes. Com o Playground configurado conforme instruções no artigo anterior, podemos agora proceder com a instalação do KEDA.
Este processo será realizado utilizando o Helm. Na documentação do KEDA, uma tabela lista as compatibilidades entre as versões da ferramenta e as versões do cluster Kubernetes.
https://keda.sh/docs/operate/cluster/#kubernetes-compatibility
A versão do Kubernetes instalada localmente no último artigo é a v1.26, por tanto iremos utilizar a versão v2.12 do KEDA.
Podemos verificar a versão do servidor local a partir do seguinte comando:
$ kubectl version
...
Server Version: v1.26.4+k3s1
Com a versão do KEDA especificada, podemos realizar a instalação executando os comandos abaixo:
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --version 2.12 --namespace keda --create-namespace
Novo template Helm
Com o KEDA instalado, iremos agora atualizar o template Helm do nosso consumer que hoje possui apenas um manifesto de Deployment. Para isso, iremos nos basear na documentação do KEDA com o scaler escolhido, em nosso caso o Apache Kafka.
Além da documentação, continuaremos utilizando o consumer construído em nosso último artigo mas agora utilizaremos um novo template Helm. Caso não tenha realizado anteriormente, é necessário clonar o seguinte repositório:
Com o repositório em mãos, utilizaremos o seguinte template helm "consumer-keda".
helm-charts/
consumer/ <-- Template antigo
...
consumer-keda/ <-- Novo template
templates/
deployment.yaml
scaler.yaml
Chart.yaml
values.yaml
Nesse novo template temos um arquivo chamado "scaler.yaml", nesse arquivo temos o seguinte manifesto seguindo a documentação do KEDA com o scaler Kafka:
Além disso, temos novos campos no arquivo "values.yaml", adicionados os campos necessários para configurarmos o scaler do Kafka.
Lembre-se de preencher o "<client_password>" que pode ser obtido a partir do seguinte comando visto no artigo anterior:
kubectl get secret kafka-user-passwords --namespace kafka -o jsonpath='{.data.client-passwords}' | base64 -d | cut -d , -f 1
Cada um dos campos tem sua função e valores padrões, além de diversos outros que podem ser configurados, segue abaixo os links da documentação do KEDA e do scaler Apache Kafka com mais detalhes sobre cada um dos campos e todos disponíveis.
https://keda.sh/docs/concepts/scaling-deployments/
https://keda.sh/docs/scalers/apache-kafka/
A customização dos valores de pollingInterval, cooldownPeriod e lagThreshold é de suma importância para o sucesso do seu consumer em um ambiente produtivo, para exemplificação os valores ficaram reduzidos a fim de facilitar os testes, em um cenário produtivo devem ser re-avaliados esses valores para cada caso.
Deploy
Com o novo template Helm, podemos realizar o deploy do nosso consumer a fim de validar seu funcionamento, para isso, execute o comando abaixo na raiz do repositório de playground para atualizarmos o template do consumer:
helm upgrade --install kafka-consumer helm-charts/consumer-keda -f helm-charts/consumer-keda/values.yaml --namespace dev-kafka-consumer --create-namespace
Com isso, podemos executar o seguinte comando para acompanhar as verificações do KEDA e validar seu funcionamento:
$ kubectl describe scaledobject -n dev-kafka-consumer
...
Hpa Name: keda-hpa-kafka-consumer
Original Replica Count: 1
Scale Target GVKR:
Group: apps
Kind: Deployment
Resource: deployments
Version: v1
Scale Target Kind: apps/v1.Deployment
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal KEDAScalersStarted 30s keda-operator Scaler kafka is built.
Normal KEDAScalersStarted 30s keda-operator Started scalers watch
Normal ScaledObjectReady 30s keda-operator ScaledObject is ready for scaling
Normal KEDAScaleTargetDeactivated 30s keda-operator Deactivated apps/v1.Deployment dev-kafka-consumer/kafka-consumer from 1 to 0
Observamos que o KEDA fez o downscaling para o mínimo de réplicas assim que foi instalado, pois não possui mensagens disponíveis para processamento.
Podemos também verificar via painel do Rancher que nosso Deployment do consumer está zerado.
Para validarmos o funcionamento do scaler, basta produzirmos uma nova mensagem no tópico do kafka.
Atualmente o "pollingInterval" do nosso scaler do KEDA é de 10 segundos, após esse intervalo o consumer será ativado a fim de processar a nova mensagem disponível no tópico do Kafka.
Com a mensagem processada, o nosso "cooldownPeriod" é de 30 segundos, após esse intervalo iniciará o processo de downscaling do consumer.
Com isso, temos nosso consumer com scaling baseado em eventos externos do Apache Kafka! 🚀
Scaling
Se pensarmos em um cenário de arquitetura orientada a eventos com milhares de processamento por hora, é importante realizarmos o scaling de réplicas do nosso Deployment baseado nas mensagens pendentes de processamento a fim de aumentarmos a eficiência do scaling.
Com esse cenário em mãos podemos continuar utilizando o KEDA apenas revisando os valores dos campos "maxReplicas", "pollingInterval", "cooldownPeriod" e "lagThreshold".
Devemos aumentar o número máximo de réplicas a fim de observarmos o scaling de réplicas, também devemos aumentar o valor de “pollingInterval”, pois pensando em um cenário de alto processamento deixa de fazer sentido um curto intervalo de verificação para scaling, além de precisarmos desse intervalo para adicionarmos as mensagens no tópico.
Como estamos apenas o log do conteúdo da mensagem processada, não iremos atualizar o campo "cooldownPeriod", pois o valor dele deve ser no mínimo o tempo máximo de processamento de uma mensagem.
E por fim o campo "lagThreshold" manteremos um valor baixo a fim de observarmos o scaling de réplicas acrescentando poucas mensagens no tópico.
Com isso, atualizamos os seguintes valores do "values.yaml":
E podemos realizar um novo deploy a partir do template executando o seguinte comando helm novamente:
helm upgrade --install kafka-consumer helm-charts/consumer-keda -f helm-charts/consumer-keda/values.yaml --namespace dev-kafka-consumer --create-namespace
Com isso, aproveitamos os 120 segundos de "pollingInterval" para produzir um total de 8 mensagens na fila.
Após aguardarmos o tempo restante do intervalo entre as verificações, é possível observar o funcionamento das configurações de scaling ao limite de réplicas.
É importante ressaltar a importância do acompanhamento e refino dos valores no ambiente produtivo a fim de configurar com eficiência o scaling
Conclusão
O KEDA é uma ferramenta poderosa que deve ter seu uso disseminado, pois tem muito potencial para um scaling eficiente de réplicas, principalmente em cenários de arquitetura orientada a eventos onde muitas as vezes não conseguimos metrificar a alta demanda de processamento apenas por métricas simples como CPU ou Memória, realizando o scaling baseado nas mensagens pendentes de processamento no tópico.
Além disso, o KEDA possui uma infinidade de scalers externos que possui compatibilidade como MySQL, MongoDB, AWS SQS, etc… Podendo ser utilizado em diversos cenários e abstraindo muitas lógicas como Cronjobs ou Jobs criados para execução a partir de uma alteração de status em um banco de dados por exemplo.
São diversos os cenários onde o KEDA pode contribuir e construirmos scalers robustos e eficientes para atender o dia a dia de milhares de serviços e aplicações.
Meu objetivo principal com esse artigo é exemplificar o uso do KEDA com um cenário de scaling baseado no Apache Kafka, mas aproveito para disseminar o potencial da ferramenta em diversos cenários.
Qualquer dúvida podem me chamar!
Obrigado pela sua atenção! E até breve 😄