Todo sistema tem limites. Quando esses limites são atingidos, o sistema entra em saturação — um estado onde a performance degrada rapidamente e de forma não-linear. O que funcionava bem com 1.000 requisições pode colapsar completamente com 1.100.
Entender saturação é fundamental para qualquer engenheiro que trabalha com sistemas em produção. Este artigo explica o que é saturação, como identificá-la, e o que fazer quando ela se aproxima.
Saturação não é quando o sistema para. É quando ele para de funcionar bem.
O que é Saturação
Saturação ocorre quando um recurso (CPU, memória, disco, rede, conexões) está sendo utilizado no limite ou além de sua capacidade.
Nesse estado:
- Filas começam a crescer
- Latência aumenta exponencialmente
- Throughput para de crescer ou diminui
- Erros começam a aparecer
A curva de saturação
Performance
│
│ ╭────────────╮
│ ╱ ╲
│ ╱ ╲
│ ╱ ╲
│ ╱ ╲
│╱ ╲
└────────────────────────────
Utilização → 100%
│←── Linear ──→│←─ Saturação ─→│
Até certo ponto, adicionar mais carga resulta em mais throughput (comportamento linear). Depois desse ponto, adicionar mais carga resulta em menos throughput e muito mais latência.
Por que a Degradação é Não-Linear
Lei de Amdahl e contenção
Quando recursos são disputados por múltiplos processos, o overhead de coordenação aumenta. Com utilização alta:
- Mais tempo é gasto em context switching
- Mais tempo esperando locks
- Mais tempo em filas
- Menos tempo fazendo trabalho útil
Teoria das filas
A relação entre utilização e tempo de espera não é linear. Segundo a teoria das filas:
Tempo de espera ∝ 1 / (1 - utilização)
Isso significa:
- Com 50% de utilização: tempo de espera = 1x
- Com 80% de utilização: tempo de espera = 4x
- Com 90% de utilização: tempo de espera = 9x
- Com 95% de utilização: tempo de espera = 19x
Um aumento de 5% na utilização (de 90% para 95%) dobra o tempo de espera.
Tipos de Saturação
Saturação de CPU
Sintomas:
- Load average alto
- Processos em estado "runnable" esperando CPU
- Latência crescente mesmo sem I/O
Causas comuns:
- Código ineficiente
- Loops infinitos ou quase-infinitos
- Serialização/deserialização pesada
- Criptografia sem aceleração de hardware
Saturação de memória
Sintomas:
- Swap ativo
- OOM kills
- Garbage collection frequente e longo
- Latência errática
Causas comuns:
- Memory leaks
- Caches sem limite
- Buffers mal dimensionados
- Muitas conexões simultâneas
Saturação de disco
Sintomas:
- I/O wait alto
- Latência de disco crescente
- Queue depth do disco alto
Causas comuns:
- Logs excessivos
- Queries sem índice
- Falta de cache
- Disco subdimensionado
Saturação de rede
Sintomas:
- Pacotes dropped
- Retransmissões TCP
- Latência variável
- Bandwidth no limite
Causas comuns:
- Payloads grandes
- Muitas conexões simultâneas
- Falta de compressão
- Network interface subdimensionada
Saturação de conexões
Sintomas:
- "Connection refused" ou timeouts
- Pool de conexões esgotado
- Threads bloqueadas esperando conexão
Causas comuns:
- Pool mal dimensionado
- Conexões não sendo liberadas
- Backend lento segurando conexões
Como Identificar Saturação
Métricas USE (Utilization, Saturation, Errors)
Para cada recurso, monitore:
- Utilization — percentual de tempo que o recurso está ocupado
- Saturation — trabalho que não pode ser atendido (filas)
- Errors — quantidade de erros relacionados ao recurso
Sinais de alerta
| Recurso | Sinal de saturação iminente |
|---|---|
| CPU | Utilização > 70% sustentada |
| Memória | Uso > 80% ou swap ativo |
| Disco | I/O wait > 20% ou queue > 1 |
| Rede | Utilização > 70% do link |
| Conexões | Pool > 80% utilizado |
Métricas derivadas
- Latência percentil 99 — sobe antes da média
- Taxa de erro — aumenta com saturação
- Throughput — para de crescer ou cai
O que Fazer Quando Saturação se Aproxima
Curto prazo (emergência)
- Shed load — rejeite requisições excedentes graciosamente
- Circuit breakers — proteja dependências
- Rate limiting — limite requisições por cliente
- Priorização — atenda primeiro o que é crítico
Médio prazo (mitigação)
- Escale horizontalmente — adicione mais instâncias
- Escale verticalmente — aumente recursos
- Otimize o gargalo — código, queries, configurações
- Adicione cache — reduza carga no recurso saturado
Longo prazo (prevenção)
- Capacity planning — projete crescimento
- Testes de carga — conheça seus limites
- Alertas proativos — seja avisado antes da saturação
- Arquitetura resiliente — design para falha graceful
Saturação Cascata
Um dos maiores perigos é a saturação em cascata: quando a saturação de um componente causa saturação em outros.
Exemplo
Banco de dados lento (saturação de disco)
↓
Aplicação segura conexões por mais tempo
↓
Pool de conexões satura
↓
Threads bloqueadas esperando conexão
↓
CPU aparentemente baixa, mas sistema parado
↓
Load balancer detecta instância "saudável" (CPU ok)
↓
Envia mais tráfego
↓
Sistema colapsa completamente
Conclusão
Saturação é o ponto onde sistemas bem comportados se tornam imprevisíveis. A diferença entre 80% e 95% de utilização pode ser a diferença entre "funcionando bem" e "caos total".
Para evitar surpresas:
- Conheça a capacidade real do seu sistema
- Monitore sinais de saturação, não apenas utilização
- Tenha planos de contingência para quando saturação acontecer
- Projete para falhar graciosamente, não catastroficamente
Um sistema bem projetado não evita saturação — ele sabe lidar com ela.