System Design: como projetar sistemas escaláveis e resilientes
Construir software vai muito além de escrever código. À medida que uma aplicação cresce, surgem desafios relacionados à escalabilidade, disponibilidade, segurança, desempenho e manutenção. É nesse contexto que entra o System Design, disciplina responsável por projetar arquiteturas capazes de atender aos requisitos atuais e futuros de um sistema.
Independentemente da tecnologia utilizada — Node.js, Java, Go, Python ou qualquer outra — os conceitos de System Design permanecem os mesmos. Entender esses princípios é essencial para desenvolvedores que desejam evoluir para posições de nível sênior, staff ou arquiteto de software.
O que é System Design?
System Design é o processo de definir a arquitetura de um sistema, incluindo seus componentes, fluxos de comunicação, armazenamento de dados e estratégias para garantir desempenho, escalabilidade e confiabilidade.
Enquanto a implementação responde à pergunta "como desenvolver uma funcionalidade?", o System Design busca responder questões como:
- Como o sistema suportará milhões de usuários?
- Como evitar pontos únicos de falha?
- Como garantir alta disponibilidade?
- Como reduzir a latência das requisições?
- Como manter os dados consistentes?
- Como integrar diferentes serviços?
O objetivo é encontrar um equilíbrio entre simplicidade, custo e capacidade de evolução.
Antes de desenhar qualquer arquitetura
Um erro comum é começar desenhando microsserviços, bancos de dados ou filas de mensagens sem entender o problema.
O primeiro passo sempre deve ser compreender os requisitos.
Requisitos funcionais
Descrevem o que o sistema deve fazer.
Exemplos:
- Cadastro de usuários
- Login
- Compra de produtos
- Upload de arquivos
- Envio de notificações
Requisitos não funcionais
Definem como o sistema deve se comportar.
Exemplos:
- Alta disponibilidade
- Escalabilidade
- Segurança
- Baixa latência
- Tolerância a falhas
- Observabilidade
- Recuperação de desastres
Na prática, são esses requisitos que mais influenciam as decisões arquiteturais.
Estimando a carga do sistema
Antes de escolher qualquer tecnologia, é importante estimar o volume esperado.
Perguntas comuns:
- Quantos usuários existirão?
- Quantos acessos simultâneos?
- Qual será o pico de utilização?
- Quanto armazenamento será necessário?
- Qual o crescimento esperado?
Imagine uma aplicação com:
- 10 milhões de usuários
- Cada usuário realiza 5 requisições por dia
Isso representa cerca de 50 milhões de requisições diárias.
Em horários de pico, o sistema pode receber milhares de requisições por segundo, influenciando diretamente decisões sobre infraestrutura, cache e banco de dados.
Comece simples
Uma boa arquitetura nasce simples.
Cliente
↓
API
↓
Banco de Dados
Não existe motivo para iniciar um projeto pequeno utilizando dezenas de microsserviços, filas e diversos bancos de dados.
A arquitetura deve evoluir conforme surgem novas necessidades.
Evoluindo a arquitetura
Com o crescimento da aplicação, novos componentes podem ser adicionados.
Uma evolução comum seria:
Cliente
↓
CDN
↓
Load Balancer
↓
API
↓
Redis
↓
Banco de Dados
Cada elemento possui uma responsabilidade específica.
CDN
Distribui arquivos estáticos geograficamente, reduzindo latência.
Load Balancer
Distribui requisições entre múltiplas instâncias da aplicação.
Cache (Redis)
Evita consultas repetitivas ao banco de dados.
Banco de Dados
Permanece responsável pela persistência das informações.
Escalabilidade
Existem duas formas principais de escalar um sistema.
Escalabilidade vertical
Consiste em aumentar os recursos do servidor.
Exemplo:
- Mais CPU
- Mais memória
- Mais armazenamento
É simples de implementar, mas possui limites físicos.
Escalabilidade horizontal
Consiste em adicionar novas instâncias da aplicação.
Load Balancer
↓
API 1
API 2
API 3
API 4
Essa abordagem permite crescer praticamente sem limites e é amplamente utilizada em aplicações modernas.
Banco de dados
A escolha do banco depende do problema.
PostgreSQL
Ideal para:
- Relacionamentos complexos
- Transações
- Integridade dos dados
MongoDB
Indicado para:
- Estruturas flexíveis
- Documentos JSON
- Evolução frequente do modelo
Redis
Excelente para:
- Cache
- Sessões
- Rate limiting
- Filas leves
Elasticsearch
Especializado em:
- Buscas
- Indexação
- Full Text Search
Nenhum banco resolve todos os problemas.
Cache
Grande parte das aplicações realiza mais leituras do que escritas.
Nesse cenário, utilizar cache reduz drasticamente a carga do banco.
Fluxo:
Cliente
↓
API
↓
Redis
↓
Banco
Caso o dado esteja no Redis, a consulta ao banco sequer acontece.
Isso reduz latência e aumenta significativamente a capacidade do sistema.
Balanceamento de carga
Quando existem várias instâncias da aplicação, é necessário distribuir as requisições.
Cliente
↓
Load Balancer
↓
API 1
API 2
API 3
Além da distribuição, o balanceador pode remover automaticamente servidores indisponíveis.
Comunicação assíncrona
Nem todo processamento precisa acontecer imediatamente.
Imagine uma compra online.
Após o pagamento, diversas tarefas podem ser executadas:
- Enviar e-mail
- Emitir nota fiscal
- Atualizar estoque
- Gerar relatório
- Notificar outros sistemas
Essas tarefas podem ser processadas por meio de filas.
Compra
↓
Fila
↓
Serviço de Email
Serviço Fiscal
Serviço de Estoque
Serviço de Notificação
Essa estratégia reduz o tempo de resposta para o usuário e melhora a escalabilidade.
Consistência dos dados
Nem todos os sistemas possuem os mesmos requisitos.
Um sistema bancário prioriza consistência.
Uma rede social geralmente prioriza disponibilidade.
Essas decisões estão diretamente relacionadas ao Teorema CAP, que afirma que sistemas distribuídos precisam equilibrar Consistência, Disponibilidade e Tolerância a Partições.
Compreender esse equilíbrio é fundamental para tomar decisões arquiteturais.
Evitando concorrência
Um problema clássico é impedir que dois usuários comprem o mesmo ingresso ou reservem o mesmo quarto de hotel simultaneamente.
Algumas estratégias incluem:
- Lock pessimista
- Lock otimista
- Transações
- Constraints únicas
- Idempotência
- Reservas temporárias
- Filas de processamento
Cada abordagem possui vantagens e limitações, e a escolha depende das características do sistema.
Segurança
Toda arquitetura deve considerar segurança desde o início.
Algumas práticas fundamentais incluem:
- HTTPS
- JWT ou OAuth 2.0 para autenticação
- Rate Limiting
- Criptografia de dados sensíveis
- Validação de entradas
- Proteção contra SQL Injection
- Proteção contra XSS
- Proteção contra CSRF quando aplicável
Segurança não deve ser tratada como uma funcionalidade adicional, mas como um requisito da arquitetura.
Observabilidade
Projetar um sistema também significa facilitar sua operação em produção.
Os três pilares da observabilidade são:
Logs
Registram eventos importantes da aplicação.
Métricas
Permitem acompanhar consumo de CPU, memória, latência, throughput e erros.
Tracing
Acompanha o caminho completo de uma requisição entre diferentes serviços.
Com essas informações é possível identificar gargalos rapidamente.
Alta disponibilidade
Um sistema moderno deve continuar funcionando mesmo diante de falhas.
Algumas estratégias incluem:
- Replicação de banco de dados
- Múltiplas instâncias da aplicação
- Balanceadores de carga
- Deploy em múltiplas zonas de disponibilidade
- Backups automáticos
- Estratégias de Disaster Recovery
Quanto menor o tempo de indisponibilidade, maior a confiabilidade do sistema.
Trade-offs
Uma das principais responsabilidades de quem projeta sistemas é compreender que toda decisão possui vantagens e desvantagens.
Exemplos:
Redis
Vantagens:
- Alta velocidade
- Redução da carga do banco
Desvantagens:
- Cache desatualizado
- Estratégias de invalidação
Microsserviços
Vantagens:
- Escalabilidade independente
- Isolamento de responsabilidades
Desvantagens:
- Complexidade operacional
- Comunicação distribuída
- Observabilidade mais difícil
Kafka
Vantagens:
- Alto throughput
- Processamento assíncrono
Desvantagens:
- Curva de aprendizado
- Maior complexidade operacional
Um bom arquiteto não escolhe apenas tecnologias populares; ele entende seus custos e benefícios.
Como estudar System Design
Uma forma eficiente de evoluir é praticar sistemas conhecidos.
Alguns exercícios interessantes são:
- Sistema de venda de ingressos
- Plataforma de streaming
- Rede social
- Aplicativo de chat
- Marketplace
- Sistema bancário
- Encurtador de URLs
- Sistema de reservas
- Plataforma de vídeos
- Serviço de compartilhamento de arquivos
Para cada problema, procure responder:
- Quais são os requisitos?
- Onde estão os gargalos?
- Como escalar?
- Como garantir disponibilidade?
- Como evitar concorrência?
- Como monitorar?
- Quais são os trade-offs?
Conclusão
System Design não consiste em decorar arquiteturas prontas ou utilizar a maior quantidade possível de tecnologias. O verdadeiro objetivo é compreender o problema, identificar restrições e projetar soluções equilibradas, capazes de evoluir conforme o crescimento da aplicação.
Comece sempre pelo mais simples, valide as necessidades reais do sistema e evolua a arquitetura de forma incremental. Essa abordagem reduz complexidade, facilita a manutenção e evita custos desnecessários.
Dominar System Design é um diferencial importante para desenvolvedores que desejam atuar em projetos de grande escala e assumir responsabilidades relacionadas à arquitetura de software. Mais do que conhecer ferramentas, é a capacidade de tomar decisões técnicas fundamentadas que diferencia um bom desenvolvedor de um excelente arquiteto.
Saiba mais
Livros
- Designing Data-Intensive Applications (DDIA) — Martin Kleppmann
Considerado um dos livros mais importantes sobre sistemas distribuídos. Aborda replicação, particionamento, consistência, processamento de dados, mensageria e armazenamento em profundidade. - System Design Interview – An Insider's Guide (Volume 1 e 2) — Alex Xu
Excelente para quem está se preparando para entrevistas, com estudos de caso como Instagram, TinyURL, YouTube, Google Drive e Uber. - Software Architecture: The Hard Parts — Neal Ford, Mark Richards, Pramod Sadalage e Zhamak Dehghani
Focado em decisões arquiteturais, sistemas distribuídos e trade-offs.
Plataformas e cursos
- ByteByteGo — Conteúdo visual de alta qualidade sobre arquitetura, bancos de dados, cache, filas e sistemas distribuídos.
- Design Gurus – Grokking the System Design Interview — Um dos cursos mais conhecidos para entrevistas de System Design.
- Exponent — Mock interviews, exemplos de entrevistas reais e preparação para empresas de grande porte.
- Educative — Cursos interativos de arquitetura, microsserviços e System Design.
Repositórios no GitHub
- System Design Primer
O repositório mais famoso sobre System Design, com conceitos fundamentais, diagramas e dezenas de estudos de caso. - Awesome System Design Resources
Uma coleção com centenas de artigos, vídeos, livros, estudos de caso e conceitos organizados por assunto. - Best System Design Resources
Reúne livros, cursos, cheatsheets, plataformas e questões de entrevistas em um único lugar.