ENGENHARIA DE SOFTWARE · LEITURA DE ~18 MIN

System Design:
as decisões que fazem um sistema crescer

Todo mundo aprende a programar. Pouca gente aprende a fazer um sistema continuar funcionando quando ele dá certo. Este artigo explica, do zero e sem pressa, as decisões que separam um projeto que roda na sua máquina de um sistema pronto para produção — e você vai poder mexer em cada conceito ao longo do texto.

CAPÍTULO 01

Quando o app cresce

Imagine que você criou um app de delivery. O código está limpo, os testes passam, e as primeiras dez pessoas usam sem nenhum problema. Cem usuários? Ainda funciona. Aí o app aparece num vídeo viral — e de repente dez mil pedidos chegam ao mesmo tempo.

O problema pode não estar na regra de negócio. Muitas vezes ele aparece quando limites de recursos e defeitos invisíveis em baixa carga — condições de corrida, vazamentos de memória, consultas N+1, locks, pools mal configurados ou algoritmos caros — começam a se manifestar. Consultas passam a esperar por conexões, locks e capacidade de processamento; novas tentativas podem piorar tudo.

DEMO · SIMULADOR DE CARGASISTEMA SAUDÁVEL
FUNCIONA BEM
APP
SERVIDOR CPU 18%
BANCO CONEXÕES 12%

Na demo, CPU e conexões de banco saturam primeiro. Na prática, são gargalos comuns — não universais. Rede, disco, memória, garbage collector, locks, thread pools, APIs externas ou limites do provedor podem ser o primeiro teto. Medir vem antes de escolher a solução.

CAPÍTULO 02

O que é System Design

Programar é resolver problemas dentro de um componente. System Design é decidir como os componentes formam um sistema: onde os dados moram, como os serviços conversam, o que acontece quando algo falha e como você descobre que falhou.

Na prática, toda decisão de design responde a uma destas sete perguntas:

  • DADOSOnde cada informação fica guardada — e quem é a fonte da verdade?
  • COMUNICAÇÃOOs serviços conversam de forma síncrona (esperando resposta) ou assíncrona (via filas)?
  • ESCALAQuando a demanda dobrar, o sistema cresce trocando a máquina ou adicionando máquinas?
  • FALHASO que acontece quando — não “se” — uma parte cair?
  • SEGURANÇAQuem pode acessar o quê, e como o sistema se protege de abuso?
  • OBSERVABILIDADEComo você enxerga o que está acontecendo lá dentro, em produção?
  • OPERAÇÃO & EVOLUÇÃOComo implantar, migrar, testar, reverter e mudar o sistema sem interromper usuários?

Nenhuma dessas perguntas tem uma resposta “certa” universal. System Design é a disciplina dos trade-offs: cada escolha compra um benefício pagando um custo, e o bom projetista sabe qual custo aceita pagar naquele momento do produto.

CAPÍTULO 03

O começo simples

Toda arquitetura famosa começou igual: um cliente, um servidor, um banco de dados. O usuário faz uma requisição, o servidor processa, consulta o banco, e a resposta volta pelo mesmo caminho.

Vale entender esse caminho com calma, porque tudo que vem depois — cache, filas, réplicas — é uma variação dele. Aperte o botão e acompanhe a requisição:

DEMO · CICLO DE UMA REQUISIÇÃOAGUARDANDO
REQUISIÇÃO → ← RESPOSTA
USUÁRIO
SERVIDOR
BANCO
1 · DNS + CONEXÃO 2 · SERVIDOR PROCESSA 3 · CONSULTA AO BANCO 4 · RESPOSTA ENTREGUE — ms

Essa arquitetura tem um nome meio injusto: “simples demais”. Para muitos produtos em estágio inicial e com carga moderada, ela é frequentemente a decisão certa. O número de usuários sozinho não decide: importam frequência de uso, custo de cada operação, volume de dados e disponibilidade exigida.

CAPÍTULO 04

Escalabilidade: uma máquina maior ou várias máquinas?

Quando um componente satura, existem dois caminhos clássicos para aumentar sua capacidade. Escala vertical: usar uma máquina mais potente. Escala horizontal: adicionar instâncias e distribuir o tráfego. Antes de ambos, existe uma pergunta ainda mais barata: podemos executar menos trabalho corrigindo consultas, índices, algoritmos, batching ou chamadas redundantes?

Vertical é simples: nada muda no código, você só paga mais. Mas tem teto (a maior máquina do mundo ainda é uma máquina) e mantém um ponto único de falha — se ela cair, tudo cai. Horizontal é elástica e resiliente, mas cobra um preço: seu código precisa aceitar que existe mais de uma instância rodando ao mesmo tempo (sessões, uploads e estado local viram problema).

DEMO · ESTRATÉGIAS DE ESCALAMAIS POTÊNCIA
SERVIDOR A16 CPU · 64 GB
SERVIDOR B4 CPU · 16 GB
SERVIDOR C4 CPU · 16 GB
CAPACIDADE PONTO ÚNICO DE FALHASIM CUSTOALTO

Na vida real, muitos sistemas usam máquinas suficientemente potentes e múltiplas instâncias atrás de um balanceador. Escala horizontal reduz a dependência de uma instância, mas não elimina pontos únicos no load balancer, banco, cache, autenticação, região ou provedor. Redundância precisa atravessar a arquitetura.

CAPÍTULO 05

Latência & throughput: rápido não é a mesma coisa que aguentar volume

Duas métricas dominam qualquer conversa de performance, e elas medem coisas diferentes. Latência é o tempo que uma requisição leva para ser respondida — a experiência de um usuário. Throughput é quantas requisições o sistema processa por segundo — a capacidade do todo.

Um sistema pode ter latência ótima com pouca gente e desmoronar com volume. O padrão clássico: a latência fica estável enquanto há capacidade sobrando e explode de forma não-linear quando o sistema se aproxima da saturação. Arraste o slider e observe o joelho da curva:

DEMO · CARGA × LATÊNCIAZONA SAUDÁVEL
LATÊNCIA (P95)85ms THROUGHPUT10req/s TAXA DE ERRO0% 
POUCOS USUÁRIOSMUITOS USUÁRIOS

Concorrência é quantas operações estão em andamento; throughput oferecido é o que chega; throughput processado é o que termina. Dez usuários simultâneos não significam dez requisições por segundo. Já o p95 é o valor abaixo do qual 95% das observações ficaram; os 5% restantes tiveram latência igual ou maior. O p99 faz o mesmo corte em 99%.

LEI DE LITTLE · L = λW

Quanto mais uma requisição demora, mais requisições ficam abertas ao mesmo tempo. Isso pressiona pools, filas e conexões — e faz a saturação alimentar a si própria.

CAPÍTULO 06

Dados, cache & CDN: o gargalo apenas mudou de lugar

Você escalou horizontalmente, tem cinco servidores atrás do load balancer… e o sistema continua lento. Por quê? Porque todos os cinco batem no mesmo banco de dados. Escalar a camada de aplicação só empurra o gargalo para baixo.

A primeira ferramenta contra isso é o cache: uma camada de memória rápida (Redis, Memcached) que guarda o resultado das consultas mais frequentes. O cardápio do restaurante não muda a cada segundo — então por que consultar o banco 12 mil vezes por minuto para responder a mesma pergunta?

DEMO · CAMADA DE CACHECACHE DESLIGADO
API
CACHE
BANCO
LATÊNCIA240 ms CONSULTAS/MIN NO BANCO12.400 CARGA DO BANCO91%

Cache não é mágica. TTL é apenas uma estratégia; também existem invalidação por evento, cache-aside, write-through, write-behind e versionamento. Cada escolha pode introduzir dados inconsistentes, hot keys, stampede, avalanche de expirações e cold start. Cache não corrige uma consulta ruim; apenas evita executá-la em algumas ocasiões.

Antes ou junto do cache, o banco pode ganhar índices, consultas melhores, pooling, batching, materialized views e desnormalização. Quando um nó já não basta, entram decisões fundamentais:

  • REPLICAÇÃOCopiar dados para tolerar falhas e escalar leituras; réplicas assíncronas podem servir dados atrasados.
  • PARTICIONAMENTODividir dados entre nós para escalar armazenamento e escrita, pagando complexidade em consultas e rebalanceamento.
  • CONSISTÊNCIADefinir quando uma escrita deve aparecer: forte, eventual ou garantias como read-your-writes.
  • CDN & OBJETOSServir imagens, cardápios e arquivos na borda para que esse trabalho nem chegue à API de origem.

CAPÍTULO 07

Comunicação assíncrona: nem tudo precisa acontecer agora

Quando o usuário toca em “fazer pedido”, o sistema pode registrar a solicitação e devolver “recebido” ou “em processamento”. Pagamento, reserva de estoque e confirmação podem ocorrer de forma assíncrona — desde que a interface não prometa uma conclusão que ainda não aconteceu. “Pedido recebido” é diferente de “pedido confirmado”.

É para isso que usamos mensageria e streaming, como RabbitMQ, SQS ou Kafka, cada um com modelos e garantias diferentes. Kafka é uma plataforma distribuída de event streaming com retenção, replay, partições e grupos de consumidores — não apenas uma fila tradicional.

DEMO · SÍNCRONO × ASSÍNCRONOSÍNCRONO · 4 ETAPAS
CLIENTEAGUARDANDO…
PAGAMENTO
ESTOQUE
RESTAURANTE
NOTIFICAÇÃO

RESPOSTA AO CLIENTE EM

O custo é projetar garantias de entrega e processamento: at-most-once, at-least-once e exatamente uma vez apenas em contextos delimitados; além de duplicidade, ordenação, retries, dead-letter queues, poison messages, particionamento e backpressure. Normalmente, não é “a mensagem” que falha: a entrega não é confirmada ou o consumidor não consegue processá-la.

CAPÍTULO 08

Resiliência: falhas vão acontecer — planeje a recuperação

Em escala, falha não é exceção, é rotina: um disco morre, um deploy quebra, um datacenter inteiro fica fora do ar. Sistema resiliente não é o que nunca falha — é o que continua atendendo enquanto falha.

O kit começa por timeout: sem um limite, uma chamada pode ficar presa indefinidamente. Depois vêm retry com backoff exponencial e jitter, circuit breaker, idempotência, isolamento ou bulkhead, degradação graciosa e failover. Retry deve tratar apenas falhas transitórias, com limite de tentativas e orçamento; caso contrário, multiplica o tráfego durante a sobrecarga.

DEMO · KIT DE RESILIÊNCIAFAILOVER ENTRE REGIÕES
REGIÃO AATIVA
REGIÃO BSTANDBY

O SERVIÇO ESTÁ INSTÁVEL · FAÇA UMA CHAMADA

API FECHADO PAGAMENTO

A MESMA MENSAGEM CHEGOU DUAS VEZES (RETRY DA FILA)

Idempotência significa que execuções equivalentes não criam efeitos adicionais no estado observável; normalmente exige chave, deduplicação, constraint única e transação. Failover regional também não é instantâneo: depende de replicação, roteamento, capacidade secundária e testes. RPO define quanto dado pode ser perdido; RTO, quanto tempo de indisponibilidade é aceitável.

Durante sobrecarga, resiliência também significa proteger capacidade: rate limits, quotas, backpressure, load shedding e prioridade podem preservar criação e pagamento de pedidos enquanto recomendações e relatórios degradam.

CAPÍTULO 09

Observabilidade: encontre o problema antes do usuário

“O app tá lento” é o pior bug report do mundo — e é o que você vai receber sem instrumentação. Observabilidade é a capacidade de investigar o estado interno a partir dos sinais emitidos. Logs, métricas e traces são fundamentais, mas só ajudam com contexto, correlação, trace IDs, cardinalidade controlada, consultas, retenção, amostragem e alertas acionáveis.

Logs contam o que aconteceu, evento por evento. Métricas mostram o comportamento agregado ao longo do tempo (CPU, latência, taxa de erro). Traces seguem uma única requisição atravessando todos os serviços — e mostram exatamente onde ela gastou tempo. Use o trace abaixo para achar o culpado de uma lentidão:

DEMO · TRACE DISTRIBUÍDOINCIDENTE ABERTO · LENTIDÃO
GATEWAY12 ms
PEDIDOS35 ms
PAGAMENTO2.400 ms
NOTIFICAÇÃO9 ms

SINTOMA: CHECKOUT LENTO · CAUSA: ?

O trace mostra que 2,4 segundos estão concentrados no serviço de pagamento. Para afirmar que a causa é um gateway externo, precisaríamos de um span filho dessa chamada; sem ele, ainda pode ser lock, banco, rede, garbage collection ou processamento interno. SLIs medem comportamento como latência e sucesso; SLOs definem objetivos como “99,9% das requisições válidas terão sucesso”.

CAPÍTULO 10

A arquitetura completa — e quando não usá-la

Junte tudo e surge uma arquitetura possível: cliente usando CDN para conteúdo estático, WAF e rate limiting protegendo a entrada, balanceador distribuindo tráfego, APIs sem estado, cache, dados replicados ou particionados e mensageria. Segurança, observabilidade, configuração e deploy não são caixas isoladas: atravessam cada componente.

SEGURANÇA · OBSERVABILIDADE · CONFIGURAÇÃO · DEPLOYAutenticação, autorização, criptografia, segredos, menor privilégio, auditoria, feature flags, rollout gradual, rollback e migrações compatíveis.
DEMO · ARQUITETURA DE PRODUÇÃOSISTEMA PARADO
CLIENTE
CDN / WAF
LB + API ×3
DADOS
CACHE
FILA

Agora, a lição mais importante do artigo: esse diagrama não é uma meta, é um repertório. Cada caixa existe para resolver um problema específico que você talvez ainda não tenha. Começar um produto novo com Kafka, cinco microsserviços e três regiões é tão errado quanto atender um milhão de usuários com um servidor só.

System Design bem feito é isso: conhecer as ferramentas, entender os trade-offs, e ter a disciplina de aplicar a solução certa para o tamanho atual do problema — deixando o caminho aberto para evoluir quando o problema crescer.

LEITURAS PARA APROFUNDAR

Google Cloud · SLIs, SLOs e percentis de latência ↗ Apache Kafka · Event streaming, retenção e consumo ↗ Amazon Builders' Library · Timeouts, retries e jitter ↗ OpenTelemetry · Observabilidade, métricas, logs e traces ↗

FIM · OBRIGADO POR LER

Quer mais conteúdo interativo?

Tem também um artigo sobre cinco grandes ideias que influenciam a busca pela AGI, nesse mesmo formato.

LER OS CINCO CAMINHOS PARA A AGI VOLTAR AOS CONTEÚDOS