Métricas customizadas costumam ser mais precisas e úteis que o autoscaling baseado em CPU e RAM, mas escalar com base em métricas customizadas e externas ainda é um terreno meio bruto, que tem muito a evoluir.

O Kubernetes é uma plataforma em constante evolução. Por isso, de tempos em tempos, eu volto a olhar com novos olhos para recursos com os quais não mexo há alguns anos. Recentemente, fiz esse exercício com Horizontal Pod Autoscalers (HPAs) e notei alguns recursos interessantes e algumas limitações que vale a pena conhecer, mas que não estão bem documentados nem são óbvios.
Uma "pegadinha" que merece destaque é que o apiVersion: autoscaling/v2 do HPA passa a impressão de que os HPAs são uma API madura. Na prática, escalar com base em métricas customizadas e externas ainda é um terreno meio bruto, que tem muito a evoluir. É uma pena, porque métricas customizadas tendem a ser mais precisas e úteis que o autoscaling baseado em CPU e RAM.
Vamos explorar alguns casos de uso em que métricas customizadas melhoram a escalabilidade e as ferramentas que tornam isso possível.
Casos de uso
Uma vez que as métricas customizadas estejam configuradas e disponíveis em um formato compatível com o HPA, os HPAs conseguem escalar com base em várias métricas. A documentação do Kubernetes traz um exemplo parcial disso: um HPA configurado para escalar com base em uso de CPU, pacotes por segundo e requisições por segundo. A ideia é que cada métrica pode sugerir um número diferente de réplicas desejadas, como 3, 5 e 8. Em seguida, o HPA escala para a maior contagem sugerida.
- O Helm chart do Kube Prometheus Stack é uma das soluções cloud-agnostic mais populares e bem suportadas para fornecer métricas customizadas. O stack reúne vários apps, e o Prometheus Adapter for Kubernetes Metrics APIs é o componente que converte e publica métricas do Prometheus em um formato que os HPAs conseguem entender e usar.
Requisições recebidas por segundo e duração/latência de requisições são métricas sólidas para escalar serviços web.
Arquiteturas com filas ou buckets de storage, em que objetos a serem processados são enviados, podem escalar automaticamente os serviços que processam esses objetos com base no número de itens detectados.
- O Kubernetes Event Driven Autoscaling (KEDA) tem scalers que se integram a várias filas ( como o Pub/Sub) e a buckets de armazenamento de objetos. Ele também permite executar queries em bancos de dados de métricas, logs, SQL e NoSQL para gerar métricas.
Mínimo variável de réplicas pode ajudar a equilibrar a capacidade de absorver picos de tráfego e o controle de custos. Se você já deu suporte a um app cujas réplicas demoram a subir ou que sofre picos enormes de tráfego, provavelmente já precisou aumentar o mínimo de réplicas para manter a qualidade do serviço.
- Por exemplo: se uma réplica suporta 100 reqs/seg, ela pode ser configurada para fazer autoscaling em 50 reqs/seg, evitando os erros ou a lentidão que aparecem acima de 100 reqs/seg. Ter um mínimo de 10 réplicas absorveria picos de tráfego melhor que um mínimo de duas.
- O único problema dessa técnica é que os custos sobem, mas é razoável imaginar que um app possa ter picos de tráfego semipredizíveis. Talvez um mínimo de duas funcione fora do horário comercial, um mínimo de 10 nos horários em que picos são comuns e um mínimo de cinco nos demais momentos.
- O KEDA incorporou recentemente uma opção para combinar várias métricas em uma fórmula personalizada pelo usuário e criar métricas compostas, plugando outras métricas em fórmulas matemáticas. Assim, contagem desejada = métrica de autoscaling + contagem desejada baseada em cron pode produzir o efeito de um mínimo variável de réplicas.
Plataformas serverless e de functions-as-a-service hospedadas no Kubernetes, como:
- keda.sh
- knative.dev
- openfaas.com
Limitações e consequências
Tudo isso soa ótimo, e existem ferramentas para colocar em prática. Então, qual é a tal limitação que impede os HPAs de serem realmente excelentes?
A limitação a seguir traz consequências significativas para a UX (experiência do usuário): https://github.com/kubernetes-sigs/custom-metrics-apiserver/issues/70
Resumindo, a limitação é: "só pode haver um servidor de métricas customizadas". Se você instalar o popular kube-prometheus-stack com as configurações padrão, terá o Prometheus Adapter. E não vai conseguir usar o keda-operator-metrics-apiserver do KEDA, o Knative Pod Autoscaler do Knative, o autoscaler do OpenFaaS Pro, o autoscaler da Datadog nem outros. Isso acontece porque todos eles funcionam hospedando um servidor de métricas customizadas. Acho que é por isso que o KEDA tem tantos scalers, a ponto de dar a impressão de querer ser o garoto-propaganda do feature creep. O KEDA tem mais de 60 scalers, incluindo um para Prometheus e outro para Datadog. Isso só faz sentido quando você percebe que parte do motivo é justamente contornar essa limitação.
Mas por que essa limitação prejudica a UX? Vamos começar com um exemplo de como é uma boa UX.
O Kube Prometheus stack e o Helm são populares por um motivo. Eles entregam uma UX excelente, e parte do segredo está em seguir o conceito de "convenção sobre configuração". Conseguem oferecer valores padrão sensatos e uma configuração padrão em que centenas, ou até milhares, de objetos YAML já vêm interligados conforme convenções, entregando uma UX turnkey em que muita coisa funciona de cara.
Um pré-requisito para que essa UX mágica aconteça é poder ter um namespace próprio que não conflite com outras coisas, pois assim dá para estabelecer convenções nele e interligar tudo previamente, sem precisar de configuração feita à mão.
Várias provas de conceito (PoCs) já foram feitas para esse problema comum, e até uma proposta de melhoria do Kubernetes foi criada para resolvê-lo; mas acabou não vingando. Espero que este artigo jogue luz sobre o problema e desperte um interesse renovado pelas APIs de scaling com métricas customizadas.