Introdução
Arquitetura de software não possui uma receita que possa ser repetida em todos os projetos.
Cada sistema apresenta:
- Requisitos próprios
- Restrições técnicas
- Limites financeiros
- Riscos diferentes
- Necessidades específicas de disponibilidade
- Requisitos de desempenho
- Diferentes níveis de maturidade técnica e operacional
Antes de escolher um padrão, uma tecnologia ou um serviço de infraestrutura, é necessário compreender:
- Qual problema precisa ser resolvido?
- Qual é a necessidade atual do negócio?
- Quais riscos precisam ser tratados agora?
- O que pode ser postergado?
- Quanto tempo de indisponibilidade é aceitável?
- A empresa possui capacidade para operar a solução proposta?
Uma arquitetura adequada resolve problemas reais sem introduzir uma complexidade que o negócio e o time ainda não precisam ou não conseguem sustentar.
Objetivos de aprendizagem
- Relacionar criticidade do negócio a disponibilidade e recuperação.
- Combinar timeout, retry, idempotência e isolamento sem ampliar falhas.
- Avaliar escalabilidade e flexibilidade junto da capacidade operacional.
Sistemas críticos e operação 24x7
Um sistema crítico precisa permanecer disponível continuamente ou apresentar um nível muito baixo de indisponibilidade.
Exemplos:
- Sistemas financeiros
- Plataformas de pagamento
- Sistemas hospitalares
- Serviços de autenticação
- Plataformas de telecomunicações
- Infraestruturas essenciais
Uma falha nesses sistemas pode gerar:
- Perdas financeiras
- Interrupção de serviços
- Riscos à segurança
- Danos à reputação
- Problemas regulatórios
- Impactos diretos aos clientes
Para sistemas com operação 24 horas por dia, sete dias por semana, a arquitetura pode precisar considerar:
- Redundância
- Resiliência
- Balanceamento de carga
- Monitoramento
- Recuperação de falhas
- Replicação de dados
- Continuidade do negócio
- Recuperação de desastres
Isso não significa que todo componente precisa necessariamente possuir o mesmo nível de disponibilidade.
O investimento deve ser proporcional à criticidade de cada parte do sistema.
Redundância
Redundância significa possuir componentes adicionais capazes de assumir a operação quando um componente principal falha.
Pode existir redundância de:
- Servidores
- Bancos de dados
- Zonas de disponibilidade
- Regiões
- Conexões de rede
- Serviços externos
O objetivo é reduzir a existência de pontos únicos de falha.
Exemplo
Considere uma aplicação executada em apenas um servidor.
Usuário
↓
Servidor único
↓
Banco de dadosSe o servidor falhar, toda a aplicação ficará indisponível.
Uma alternativa redundante pode possuir múltiplas instâncias:
Usuário
↓
Load balancer
├── Instância A
├── Instância B
└── Instância CSe uma instância apresentar falha, as demais podem continuar atendendo às requisições.
Redundância, entretanto, não garante automaticamente resiliência.
Também é necessário detectar falhas, retirar componentes indisponíveis e garantir que os dados permaneçam consistentes.
Resiliência
Resiliência é a capacidade de um sistema:
- Suportar falhas
- Continuar operando parcialmente
- Recuperar-se automaticamente
- Evitar a propagação de erros
- Retornar ao estado normal
Um sistema resiliente não é aquele que nunca falha.
É aquele que foi projetado considerando que falhas acontecerão.
Exemplo
Considere um sistema de pedidos que depende de um serviço de envio de e-mails.
Se o serviço de e-mail ficar indisponível, a criação do pedido não deveria necessariamente falhar.
Uma abordagem resiliente pode:
- Registrar o pedido.
- Publicar uma mensagem para envio posterior.
- Responder ao cliente.
- Reprocessar o envio quando o serviço estiver disponível.
A falha de um componente secundário não precisa interromper toda a jornada principal.
Balanceamento de carga
Load balancing, ou balanceamento de carga, distribui requisições entre múltiplas instâncias de uma aplicação.
Isso permite:
- Distribuir o tráfego
- Evitar sobrecarga em um único servidor
- Retirar instâncias com falha
- Aumentar a disponibilidade
- Apoiar a escalabilidade horizontal
O balanceador pode utilizar diferentes critérios de distribuição, como:
- Quantidade de conexões
- Ordem circular
- Capacidade da instância
- Tempo de resposta
- Localização geográfica
Health checks
Para evitar o envio de requisições a uma instância indisponível, o balanceador pode executar verificações de saúde.
Load balancer
↓
Health check
├── Instância A: saudável
├── Instância B: indisponível
└── Instância C: saudávelA instância com falha é temporariamente retirada da distribuição.
Resiliência básica com retries
Retry é a tentativa de repetir uma operação que falhou temporariamente.
Exemplo:
Aplicação chama serviço externo
↓
Serviço não responde
↓
Aplicação aguarda
↓
Nova tentativa é realizadaEssa estratégia pode ser útil para falhas transitórias, mas precisa ser controlada.
Limite de tentativas
As tentativas devem possuir um limite.
Sem esse controle, uma operação pode ser repetida indefinidamente, consumindo:
- Processamento
- Conexões
- Memória
- Capacidade do serviço dependente
- Tempo do usuário
Exemplo conceitual:
const MAX_ATTEMPTS = 3;
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
try {
return await executeOperation();
} catch (error) {
if (attempt === MAX_ATTEMPTS) {
throw error;
}
}
}Na prática, bibliotecas e plataformas especializadas costumam fornecer políticas mais completas de retry.
Exponential backoff
As novas tentativas não devem necessariamente ocorrer de maneira imediata.
Com exponential backoff, o intervalo aumenta progressivamente.
Primeira nova tentativa: 1 segundo
Segunda nova tentativa: 2 segundos
Terceira nova tentativa: 4 segundos
Quarta nova tentativa: 8 segundosEsse intervalo reduz a pressão sobre o serviço que está tentando se recuperar.
function calculateDelay(attempt: number): number {
return 2 ** attempt * 1_000;
}Jitter
Jitter adiciona uma variação aleatória ao intervalo entre tentativas.
Sem jitter, milhares de instâncias podem repetir a mesma chamada simultaneamente.
Serviço volta a responder
↓
Milhares de clientes tentam novamente ao mesmo tempo
↓
Novo pico de carga
↓
Serviço falha novamenteCom jitter, as tentativas são distribuídas ao longo do tempo.
function calculateDelayWithJitter(attempt: number): number {
const exponentialDelay = 2 ** attempt * 1_000;
const jitter = Math.random() * 500;
return exponentialDelay + jitter;
}Idempotência
Uma operação idempotente pode ser executada repetidamente sem produzir efeitos adicionais incorretos.
Considere um pagamento.
Um retry não pode cobrar o cliente duas vezes.
Uma forma de proteger esse fluxo é utilizar uma chave de idempotência:
await paymentService.charge({
idempotencyKey: "order-879-payment",
orderId: "order-879",
amount: 150,
});Se a mesma solicitação for recebida novamente, o serviço reconhece que a operação já foi processada.
Falhas transitórias e permanentes
Retries devem ser utilizados principalmente para falhas temporárias.
Falhas transitórias
- Timeout
- Instabilidade de rede
- Serviço momentaneamente indisponível
- Limitação temporária de capacidade
- Falha breve de conexão
Falhas permanentes
- Credenciais inválidas
- Dados incorretos
- Recurso inexistente
- Regra de negócio rejeitada
- Permissão insuficiente
Repetir uma requisição com credenciais inválidas não resolverá o problema.
Mensageria e processos assíncronos
Mensageria permite processar uma operação posteriormente, sem obrigar o sistema de origem ou o usuário a esperar por todo o fluxo.
Considere a confirmação de uma compra:
Cliente confirma compra
↓
Sistema registra pedido
↓
Mensagem é publicada
↓
Resposta é enviada ao cliente
↓
E-mail, estoque e nota são processados posteriormenteEsse modelo reduz o acoplamento temporal entre os componentes.
Benefícios
- Processamento assíncrono
- Maior tolerância a falhas
- Redução do acoplamento
- Controle de picos de demanda
- Reprocessamento
- Escalabilidade dos consumidores
- Maior resiliência
Cuidados
- Mensagens duplicadas
- Ordem de processamento
- Idempotência
- Dead-letter queues
- Monitoramento das filas
- Consistência eventual
- Rastreabilidade
- Contratos entre produtores e consumidores
Absorvendo picos de demanda
Uma fila pode funcionar como um amortecedor entre produtores e consumidores.
Produtores
↓
Fila
↓
ConsumidoresDurante um pico, os produtores continuam publicando mensagens.
Os consumidores processam os itens conforme sua capacidade.
Isso reduz a necessidade de todos os componentes escalarem simultaneamente.
Dead-letter queue
Uma dead-letter queue armazena mensagens que não puderam ser processadas após as tentativas permitidas.
Fila principal
↓
Tentativas de processamento
↓
Falha persistente
↓
Dead-letter queueEla permite:
- Investigar mensagens problemáticas
- Evitar bloqueio da fila principal
- Corrigir falhas
- Realizar reprocessamento controlado
- Preservar rastreabilidade
Escalabilidade vertical
Escalar verticalmente significa aumentar a capacidade de uma única máquina.
Exemplos:
- Aumentar memória
- Adicionar processadores
- Utilizar uma máquina mais potente
- Aumentar capacidade de disco
Vantagens
- Implementação mais simples
- Poucas mudanças na aplicação
- Menor complexidade distribuída
- Resposta rápida para problemas imediatos de capacidade
Limitações
- Existe um limite físico
- Máquinas maiores costumam custar mais
- Pode manter um ponto único de falha
- Pode exigir indisponibilidade durante a alteração
- Não distribui carga entre instâncias
Escalabilidade horizontal
Escalar horizontalmente significa adicionar novas instâncias ao sistema.
Em vez de utilizar um servidor muito grande, a aplicação utiliza múltiplos servidores trabalhando em conjunto.
Vantagens
- Maior disponibilidade
- Distribuição de carga
- Crescimento gradual
- Substituição de instâncias com falha
- Melhor adequação a variações de demanda
Limitações
- Maior complexidade
- Necessidade de balanceamento de carga
- Gerenciamento de sessões
- Sincronização de dados
- Observabilidade distribuída
- Possíveis problemas de consistência
Comparando escalabilidade vertical e horizontal
| Escala vertical | Escala horizontal |
|---|---|
| Aumenta a capacidade de uma máquina | Aumenta o número de máquinas |
| Mais simples inicialmente | Mais complexa |
| Possui limite físico | Possui maior potencial de crescimento |
| Pode manter ponto único de falha | Favorece redundância |
| Menos problemas distribuídos | Exige coordenação entre instâncias |
A escolha depende de:
- Custo
- Urgência
- Características da aplicação
- Maturidade operacional
- Necessidade de disponibilidade
- Crescimento esperado
Complexidade como possível sinal de problema
Uma observação importante da live foi:
Nem toda complexidade é desnecessária.
Sistemas críticos, regulados e distribuídos podem exigir soluções sofisticadas.
O alerta está em adotar complexidade antes de existir uma justificativa concreta.
Perguntas necessárias
- Precisamos realmente disso?
- Existe uma solução mais simples?
- O requisito exige essa complexidade?
- Estamos resolvendo um problema atual ou imaginário?
- O time conseguirá manter a solução?
- O retorno compensa o custo?
- A tecnologia foi escolhida por necessidade ou por moda?
A solução mais simples que atende corretamente aos requisitos tende a ser mais fácil de:
- Construir
- Testar
- Operar
- Explicar
- Manter
- Evoluir
Resolver o problema atual sem impedir a evolução
A arquitetura deve responder às necessidades atuais do negócio.
Isso não significa ignorar completamente o futuro.
O equilíbrio está entre:
- Não construir uma solução incapaz de evoluir
- Não antecipar uma complexidade que talvez nunca seja necessária
Exemplo
Uma startup com poucos usuários pode não precisar começar com:
- Dezenas de microsserviços
- Kubernetes
- Arquitetura multirregional
- Event sourcing
- Diversos bancos de dados
- Uma grande plataforma de observabilidade
Um monólito modular, com limites claros entre domínios, pode atender melhor ao momento e preservar possibilidades de evolução.
Pensar na sustentação
A arquitetura não termina quando o projeto é entregue.
O sistema precisará ser:
- Monitorado
- Corrigido
- Atualizado
- Protegido
- Escalado
- Depurado
- Mantido por outras pessoas
- Recuperado em caso de falha
Por isso, sustentação e operação precisam ser consideradas desde o início.
Questões operacionais
- Quem atenderá os incidentes?
- Como os erros serão identificados?
- Existem logs suficientes?
- Há métricas e alertas?
- O time possui acesso adequado aos ambientes?
- Existe documentação?
- Como uma alteração será revertida?
- Como os dados serão recuperados?
- Quanto custa manter a solução?
- O time domina as tecnologias escolhidas?
Uma arquitetura sofisticada pode se tornar uma decisão inadequada quando a empresa não possui pessoas, processos ou recursos para operá-la.
Operabilidade como requisito
Operabilidade é a facilidade com que um sistema pode ser implantado, observado, mantido e recuperado.
Ela envolve:
- Observabilidade
- Automação
- Runbooks
- Deploy seguro
- Rollback
- Gestão de incidentes
- Controle de configuração
- Gestão de capacidade
Cloud, custos e arquiteturas híbridas
Muitas empresas adotaram computação em nuvem buscando:
- Elasticidade
- Velocidade de provisionamento
- Escalabilidade
- Serviços gerenciados
- Redução da infraestrutura local
Entretanto, Cloud não representa automaticamente economia.
Os custos podem aumentar devido a:
- Recursos ociosos
- Tráfego de dados
- Serviços gerenciados
- Armazenamento
- Logs excessivos
- Máquinas superdimensionadas
- Arquiteturas distribuídas
- Execução de modelos de inteligência artificial
- Ausência de governança financeira
Arquitetura híbrida
Uma arquitetura híbrida combina diferentes ambientes:
- Infraestrutura local
- Nuvem pública
- Nuvem privada
- Serviços de terceiros
Possíveis motivos
- Controle de custos
- Requisitos regulatórios
- Baixa latência
- Dependência de sistemas legados
- Residência de dados
- Segurança
- Previsibilidade de cargas
- Continuidade operacional
A decisão não deve ser tratada como uma disputa entre Cloud e infraestrutura local.
A pergunta mais adequada é:
Qual combinação oferece o melhor equilíbrio entre custo, segurança, desempenho, flexibilidade e capacidade operacional?
Inteligência artificial e custos de infraestrutura
Soluções de inteligência artificial podem exigir:
- GPUs
- Grande volume de memória
- Armazenamento
- Transferência de dados
- Bancos vetoriais
- Processamento de documentos
- Chamadas frequentes a modelos
- Treinamento ou ajuste
- Monitoramento especializado
A adoção precisa ser orientada por retorno e necessidade.
Perguntas importantes
- O problema realmente exige IA?
- Um modelo menor seria suficiente?
- É necessário treinar um modelo próprio?
- O custo por requisição é sustentável?
- Existe uma solução determinística mais simples?
- Qual ganho concreto será produzido?
- Como o consumo será controlado?
Regra de negócio como norte da arquitetura
Regras e prioridades do negócio orientam decisões técnicas.
Um requisito de baixa latência pode ser tratado com:
- Mudança de região
- Cache
- CDN
- Replicação
- Processamento local
- Redução de chamadas externas
- Otimização de banco de dados
- Processamento assíncrono
Cada alternativa possui consequências.
Exemplo: mudança de região
Hospedar a aplicação mais próxima dos usuários pode reduzir a latência.
Entretanto, essa decisão pode:
- Aumentar custos
- Exigir replicação de dados
- Criar desafios de consistência
- Gerar custos de transferência
- Exigir atendimento a regras de residência de dados
- Aumentar a complexidade operacional
A decisão depende da importância da latência para o negócio.
Disponibilidade e tolerância à indisponibilidade
Antes de construir uma arquitetura altamente redundante, é necessário compreender quanto tempo o sistema pode permanecer indisponível.
Perguntas relevantes:
- O sistema pode ficar fora por alguns segundos?
- Alguns minutos são aceitáveis?
- Uma hora de indisponibilidade é aceitável?
- Qual é o prejuízo durante a interrupção?
- Existem processos manuais alternativos?
- Todos os componentes precisam da mesma disponibilidade?
Nem todo sistema precisa operar 24x7.
Disponibilidade possui custo
Quanto maior a exigência de disponibilidade, maior tende a ser o investimento em:
- Redundância
- Replicação
- Monitoramento
- Automação
- Equipes de suporte
- Recuperação de desastres
- Infraestrutura multirregional
Uma disponibilidade extremamente elevada pode ser tecnicamente possível e, ao mesmo tempo, financeiramente injustificável.
RTO — Recovery Time Objective
RTO representa o tempo máximo aceitável para restaurar um serviço após uma interrupção.
Exemplo:
O RTO influencia decisões sobre:
- Recuperação automática
- Redundância
- Automação
- Estratégia de failover
- Equipe de suporte
- Recuperação multirregional
RPO — Recovery Point Objective
RPO representa a quantidade máxima aceitável de dados que pode ser perdida.
Exemplo:
O RPO influencia:
- Frequência de backups
- Replicação
- Persistência
- Estratégias de recuperação
- Sincronização de dados
RTO e RPO na prática
Considere dois cenários.
Sistema A
RTO: 24 horas
RPO: 12 horasEsse sistema pode utilizar uma estratégia de recuperação mais simples e econômica.
Sistema B
RTO: 5 minutos
RPO: próximo de zeroEsse sistema pode exigir:
- Replicação contínua
- Failover automatizado
- Redundância
- Monitoramento intenso
- Infraestrutura adicional
- Procedimentos frequentes de teste
Quanto menores os valores de RTO e RPO, maior tende a ser o custo da solução.
Trade-offs exemplificados
Baixa latência versus custo
Aproximar os recursos dos usuários pode reduzir o tempo de resposta, mas aumentar custos de infraestrutura, transferência e replicação.
Alta disponibilidade versus simplicidade
Adicionar redundância melhora a disponibilidade, mas aumenta a complexidade de implantação, monitoramento e recuperação.
Processamento assíncrono versus consistência imediata
Mensageria aumenta resiliência e desacoplamento, mas pode introduzir consistência eventual.
Escalabilidade horizontal versus complexidade
Adicionar instâncias permite crescer, mas exige coordenação, balanceamento, sincronização e observabilidade distribuída.
Cloud versus previsibilidade financeira
Cloud oferece elasticidade, mas pode gerar custos variáveis e difíceis de controlar.
Solução genérica versus necessidade atual
Construir para todas as possibilidades futuras aumenta a flexibilidade teórica, mas pode atrasar a entrega e elevar custos.
Checklist para uma decisão arquitetural
Antes de adicionar uma solução de resiliência, disponibilidade ou escalabilidade, pergunte:
Problema
- Qual problema real será resolvido?
- Ele já existe ou é apenas uma possibilidade futura?
- Qual é seu impacto para o negócio?
Disponibilidade
- Quanto tempo de indisponibilidade é aceitável?
- Qual é o RTO?
- Qual é o RPO?
- Existe uma alternativa manual?
Escalabilidade
- Qual é a carga média?
- Existem picos?
- Escala vertical seria suficiente?
- A aplicação está preparada para múltiplas instâncias?
Resiliência
- A falha é transitória?
- Retry é apropriado?
- A operação é idempotente?
- Existe risco de retry storm?
- Uma fila poderia desacoplar o processo?
Operação
- Quem monitorará a solução?
- Existem logs, métricas e alertas?
- Como será realizado o rollback?
- O time domina as tecnologias?
- O custo operacional é sustentável?
Conclusão
Arquitetura é uma disciplina de decisões contextuais.
Sistemas críticos e disponíveis continuamente podem exigir:
- Redundância
- Resiliência
- Balanceamento de carga
- Mensageria
- Retries controlados
- Escalabilidade
- Recuperação de falhas
Esses recursos, entretanto, não devem ser adotados automaticamente.
Antes de aumentar a complexidade, o arquiteto precisa compreender:
- O problema real
- A criticidade do sistema
- A tolerância à indisponibilidade
- A latência esperada
- O custo aceitável
- A capacidade operacional do time
- O retorno para o negócio
Arquitetura não trata apenas de construir um sistema.
Também trata de garantir que ele possa ser operado, sustentado, recuperado e evoluído.
A boa arquitetura não é aquela que utiliza todos os recursos disponíveis, mas aquela que utiliza os recursos necessários para atender ao negócio com segurança e capacidade de evolução.
Decisão por cenário
Cenário: dependência externa instável
Uma API de pagamentos está lenta, e tentativas simultâneas começam a ocupar todos os recursos da aplicação.
Revisão do artigo
Pontos principais
- — Confiabilidade nasce de limites, isolamento e operação preparada.
- — Retry só é seguro com limite, backoff, jitter e idempotência.
- — Disponibilidade e escala devem ser proporcionais ao impacto do negócio.