Em ambientes Kubernetes, uma única configuração pode desequilibrar completamente a distribuição de requisições entre instâncias. Recentemente, enfrentamos uma situação onde alguns Pods processavam volumes massivos de tráfego enquanto outros permaneciam praticamente ociosos, comprometendo a performance e a eficiência do cluster.
A resolução foi imediata através de um comando simples:
kubectl patch svc nome-do-servico -n <namespace> --type=merge -p '{"spec":{"sessionAffinity":"None"}}'
Embora o incidente tenha sido resolvido, compreender as causas subjacentes é fundamental para prevenir recorrências. Este artigo detalha o processo investigativo, explica o funcionamento interno do mecanismo de afinidade de sessão e apresenta estratégias para mitigação e prevenção.
Fundamentos do Session Affinity
Conceito e Funcionamento
Session Affinity, também conhecido como sticky sessions, é um mecanismo de balanceamento do Kubernetes que associa requisições de um mesmo cliente a um Pod específico. Quando configurado como sessionAffinity: ClientIP, o kube-proxy direciona todas as requisições originadas de um mesmo endereço IP para o mesmo endpoint durante o período de timeout configurado.
Comportamentos de Balanceamento
Distribuição padrão (round-robin):
apiVersion: v1
kind: Service
metadata:
name: api-gateway
spec:
selector:
component: backend-api
ports:
- port: 8080
targetPort: http
# sessionAffinity ausente ou definido como "None"
Afinidade por IP do cliente:
apiVersion: v1
kind: Service
metadata:
name: api-gateway
spec:
selector:
component: backend-api
ports:
- port: 8080
targetPort: http
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 7200
Nota técnica: O valor padrão de 10800 segundos (3 horas) aplica-se exclusivamente ao modo iptables do kube-proxy. Em implementações com IPVS, o comportamento de expiração pode variar conforme a versão do kernel e do próprio IPVS.
Análise das Causas de Desbalanceamento
A configuração inadequada de Session Affinity em serviços stateless representa um dos principais gargalos de distribuição de carga. Os fatores críticos incluem:
Concentração de Endereços de Origem
Em arquiteturas modernas, o tráfego dos usuários finais atravessa múltiplas camadas de infraestrutura — CDNs, WAFs, load balancers corporativos e gateways NAT. Essa topologia resulta na agregação de milhares de requisições distintas em um conjunto reduzido de IPs de origem.
Com Session Affinity ativado, cada IP concentrado é mapeado estáticamente para um único Pod, criando cenários de distribuição assimétrica onde:
- Alguns Pods acumulam conexões excessivas, atingindo limites de recursos
- Outros Pods operam com utilização mínima, desperdiçando capacidade provisionada
Impacto Amplificado por Conexões Persistentes
Protocolos como HTTP/2 e WebSockets mantêm canais de comunicação abertos por períodos prolongados. Sob Session Affinity, todas as requisições multiplexadas nessas conexões são roteadas obrigatoriamente ao mesmo destino, impedindo qualquer redistribuição dinâmica de carga mesmo durante picos de demanda.
Metodologia de Diagnóstico
Para investigação estruturada de desbalanceamento de tráfego:
flowchart TD
A[Observar assimetria de carga entre Pods] --> B{Verificar configuração do Service}
B -->|sessionAffinity: ClientIP| C[Desativar ou reconfigurar afinidade]
B -->|sessionAffinity: None| D[Investigar outros fatores:<br></br>- Estado dos Endpoints<br></br>- Modo do kube-proxy<br></br>- Health checks]
C --> E[Validar normalização do tráfego]
D --> E
Passos de Verificação
Inspeção da configuração do Service:
kubectl get svc <nome-servico> -n <namespace> -o jsonpath='{.spec.sessionAffinity}{"\n"}'
Verificação dos Endpoints ativos:
kubectl describe endpoints <nome-servico> -n <namespace>
Análise de métricas de distribuição:
Utilize consultas PromQL para identificar disparidades:
sum(rate(container_network_receive_packets_total{pod=~"meu-app-.*"}[5m])) by (pod)
Estratégias de Correção e Otimização
Abordagem 1: Eliminação da Afinidade (Serviços Stateless)
Para workloads sem necessidade de persistência de sessão, a solução mais eficaz é a remoção completa do Session Affinity.
Correção pontual via linha de comando:
kubectl patch service <nome-servico> -n <namespace> --type=merge -p '{"spec":{"sessionAffinity":"None"}}'
Correção em lote para múltiplos serviços:
for svc in $(kubectl get svc -n <namespace> -o name); do
kubectl patch "$svc" -n <namespace> --type=merge -p '{"spec":{"sessionAffinity":"None"}}'
done
Confirmação da alteração:
kubectl get service <nome-servico> -n <namespace> -o custom-columns='NAME:.metadata.name,AFFINITY:.spec.sessionAffinity'
Abordagem 2: Controel Granular de Sessões
Quando a persistência de sessão é mandatória, considere alternativas mais sofisticadas:
Redução do período de timeout:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 600 # 10 minutos
Sessões baseadas em cookie via Ingress Nginx:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: aplicacao-web
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "K8S_SESSION"
nginx.ingress.kubernetes.io/session-cookie-expires: "1800"
nginx.ingress.kubernetes.io/session-cookie-max-age: "1800"
nginx.ingress.kubernetes.io/session-cookie-path: "/api"
spec:
rules:
- host: app.exemplo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend-svc
port:
number: 80
Balanceamento inteligente com Istio:
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: politica-balanceamento
spec:
host: servico-backend
trafficPolicy:
loadBalancer:
simple: LEAST_REQUEST
localityLbSetting:
enabled: true
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 50
outlierDetection:
consecutiveErrors: 3
interval: 5s
baseEjectionTime: 30s
Diretrizes Preventivas
Definição de Políticas de Configuração
Estabeleça critérios claros antes de implementar Session Affinity:
| Tipo de Serviço | Recomendação | Justificativa |
|---|---|---|
| APIs REST stateless | Sem afinidade | Maximiza distribuição de carga |
| Aplicações com estado em memória | Cookie-based via Ingress | Balanceia granularidade e persistência |
| WebSockets/Streaming | ClientIP com timeout curto | Mantém conexão com tolerância a failover |
| Bancos de dados, caches | StatefulSet + headless service | Identidade de rede persistente |
Integração em Pipelines de CI/CD
Incorpore validações automatizadas:
#!/bin/bash
# script-verificacao-svc.sh
ARQUIVO_SVC=$1
if grep -q "sessionAffinity: ClientIP" "$ARQUIVO_SVC"; then
echo "AVISO: Session Affinity detectado em serviço stateless"
echo "Requer aprovação manual ou justificativa documentada"
exit 1
fi
Monitoramento Proativo
Configure alertas para detectar assimetria:
- alert: PodTrafficImbalance
expr: |
(
max by (service) (rate(container_network_receive_packets_total[5m]))
/
min by (service) (rate(container_network_receive_packets_total[5m]) > 0)
) > 3
for: 10m
labels:
severity: warning
annotations:
summary: "Distribuição desigual de tráfego detectada"
Considerações Finais
A configuração de Session Affinity exemplifica como parâmetros aparentemente simples no Kubernetes podem gerar impactos significativos na operação de sistemas distribuídos. A lição fundamental é: compreenda o comportamento de cada configuração antes de aplicá-la em produção.
Para arquitetos e engenheiros de plataforma, recomenda-se:
- Manter documentação atualizada sobre decisões de configuração de networking
- Implementar testes de carga que simulem topologias reais de entrada de tráfego
- Revisar periodicamente configurações de Services em busca de desvios dos padrões estabelecidos
A capacidade de diagnosticar rapidamente a origem de desbalanceamentos — e aplicar correções cirúrgicas — diferencia operações maduras de Kubernetes de implementações frágeis sujeitas a interrupções imprevisíveis.