Pular para o conteúdo principal

Escala automática com KEDA

O escalador dos módulos é o KEDA, com gatilhos de CPU e memória apenas. Não há HPA próprio: o chart renderiza um único ScaledObject canônico, e um HPA escrito à mão no chart é recusado.

Para um NNS helm em JVM, o bloco de autoscaling é obrigatório no nnp/placement.yaml:

placement: {class: core}
resources: {requests: {cpu: 250m, memory: 512Mi}, limits: {cpu: "1", memory: 768Mi}}
replicas: 2
autoscaling: {max_replicas: 2, cpu: {target_utilization: 70}, memory: {target_utilization: 85}}
campoo que éregra
max_replicaso teto de réplicas≥ replicas
cpu.target_utilizationa utilização-alvo de CPU, em % do requestao menos um gatilho é exigido
memory.target_utilizationa utilização-alvo de memória, em % do request—
replicas (raiz)as réplicas de repouso, e também o MÍNIMO2 no padrão

O que o chart renderiza​

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: {{ $.Values.nnumbers.module.release_name }}
spec:
scaleTargetRef: {apiVersion: apps/v1, kind: Deployment, name: {{ $.Values.nnumbers.module.release_name }}}
minReplicaCount: {{ .min_replicas }}
maxReplicaCount: {{ .max_replicas }}
triggers:
- {type: cpu, metricType: Utilization, metadata: {value: "70"}}
- {type: memory, metricType: Utilization, metadata: {value: "85"}}

O ScaledObject é canônico: nome igual ao da release, alvo no Deployment da release, minReplicaCount = min_replicas (= replicas do placement) e maxReplicaCount explícitos, só gatilhos cpu/memory com metricType: Utilization. Não há idleReplicaCount, fallback, advanced, pollingInterval nem cooldownPeriod — qualquer um deles é chart_autoscaling_mismatch.

O objeto só é renderizado com nnumbers.autoscaling.enabled: um target sem KEDA mantém as réplicas fixas no mínimo.

As duas regras que não se negociam​

  • minReplicaCount >= 1. Não existe escala para zero: um NNS de módulo é um serviço de plataforma, não um job. Zero réplica significaria rota registrada sem processo atrás.
  • Só CPU e memória. Sem gatilho de fila, de evento ou de métrica de aplicação. Escalar por CPU/memória é previsível e não depende de um componente a mais no caminho da requisição; quando a vazão não cresce com réplica, o problema é outro (banco, dependência, tarefa única) e escalar não resolve.

Como o mínimo foi escolhido, na prática​

módulomínimo × máximopor quê
demo (referência)2 × 4prova de escala sob carga: 2 → 4
iam2 × 2o trabalho é limitado pelo banco e pelo provedor de identidade; réplica a mais só soma sondas e tarefas periódicas
tenants2 × 2idem

O mínimo 2 é de disponibilidade: com 1 réplica, o desligamento de um pod (drain, atualização) deixa o módulo sem processo. Um componente com deployment: external e chart próprio não é obrigado ao ScaledObject canônico — ele pode trazer um ScaledObject opcional, desligado por padrão.

Duas restrições que você precisa conhecer​

O pod do Job de migração conta no escalador. O Job leva os mesmos labels de módulo e release do Deployment (são obrigatórios), e o escalador enxerga o pod dele: um HPA ficou 12 minutos sem reduzir por causa disso. A correção no contrato do chart é pôr ttlSecondsAfterFinished obrigatório no Job ou manter os labels do Job fora do seletor.

Upgrade no lugar com KEDA não é suportado. O chart check exige replicas mesmo com autoscaling, e o Helm dá conflito em .spec.replicas quando há um HPA ativo. Isso não atinge o caminho normal: o Module Manager instala uma release nova por versão, nunca upgrade no lugar. Se você for fazer upgrade manual de chart com KEDA ligado, você está fora do caminho suportado.

Gatilho em memória e o limite da JVM​

O gatilho de memória usa a utilização em relação ao request — não ao limite. Com request: 512Mi e target_utilization: 85, o alvo é ~435 Mi de uso, acima do RSS típico (180–251 Mi) e do pico (288 Mi). O número só faz sentido junto com os valores de Recursos e limites: se você mudar o request, o gatilho muda de significado.

Onde conferir​

./nnconsolew descriptors validate --dir nnp # o bloco autoscaling é válido
./nnconsolew chart check --values nns/helm/testdata/injected-values.yaml --namespace <ns> \
--runtime jvm --runtime-user 1002 nns/helm/chart

O chart check recusa chart_autoscaling_mismatch quando o ScaledObject foge da forma canônica — inclusive passando um maxReplicaCount diferente do max_replicas do placement.