| Bellacosa Mainframe e o kubernetes encontrando o cobol |
☕ Um Café no Bellacosa Mainframe
A Bússola de Ouro do System Design — Quando Lyra Entrou no Data Center, Igor Instalou Kubernetes e o Daemon do COBOL Descobriu que Complexidade Também Tem Poeira
Ou: um jovem padawan recebeu um servidor, um monólito e um banco SQL; atravessou a Faca Sutil dos microsserviços, encontrou Kafka entre dois mundos e aprendeu que o verdadeiro arquiteto não é quem instala todas as tecnologias, mas quem sabe quais portas jamais deveriam ser abertas
Prólogo — Há mais de um mundo dentro do data center
Imagine que você é um programador COBOL iniciante caminhando pelos corredores de um grande data center.
De um lado, encontra o mundo aparentemente sólido do mainframe: z/OS, CICS, Db2, IMS, VSAM, JCL, RACF, MQ e toneladas de transações passando silenciosamente por processadores que não precisam aparecer no LinkedIn a cada quinze minutos para provar que estão trabalhando.
Do outro, enxerga o mundo distribuído moderno: APIs, containers, Kubernetes, microsserviços, Redis, Kafka, MongoDB, GraphQL, Terraform, Prometheus, Grafana, service mesh e uma procissão de tecnologias com nomes que parecem demônios, constelações ou grupos de rock progressivo.
Entre esses mundos existe uma espécie de Faca Sutil: a arquitetura de sistemas.
Quando usada com inteligência, ela abre passagens úteis entre plataformas, equipes e aplicações. Quando usada sem experiência, corta fronteiras que deveriam permanecer inteiras, espalha dados por vinte serviços e deixa o operador de produção tentando descobrir em qual universo a transação desapareceu.
É essa a grande mensagem da discussão sobre System Design: a tecnologia moderna não tornou inúteis as soluções antigas. Ela apenas criou novas maneiras de distribuir responsabilidades — e, junto com elas, novas maneiras de distribuir problemas.
A série His Dark Materials, baseada na obra de Philip Pullman, acompanha Lyra Belacqua numa travessia por mundos conectados, autoridades que controlam o conhecimento, instrumentos cuja leitura exige experiência e uma misteriosa substância chamada Pó. A produção protagonizada por Dafne Keen adotou uma atmosfera mais sombria que a adaptação cinematográfica de 2007, contando também com nomes como James McAvoy, Ruth Wilson e Lin-Manuel Miranda. O roteiro ficou sob responsabilidade de Jack Thorne.
Nossa Lyra, porém, não carregará apenas um aletiômetro.
Ela levará um dump, um diagrama de arquitetura e a recomendação mais importante do velho urso de armadura que trabalha no suporte:
“Antes de instalar qualquer coisa, descubra qual problema está tentando resolver.”
1. O aletiômetro da arquitetura
Em His Dark Materials, o aletiômetro parece uma bússola, mas não aponta simplesmente para o norte. Seus símbolos precisam ser interpretados em diferentes níveis. A pergunta correta é tão importante quanto a leitura do instrumento.
System Design funciona do mesmo modo.
Um arquiteto não começa perguntando:
Devemos usar Kubernetes?
Devemos criar microsserviços?
Kafka ou RabbitMQ?
MongoDB ou Cassandra?
REST, GraphQL ou gRPC?
Quantos clusters devemos criar?
Ele começa perguntando:
Qual problema de negócio estamos resolvendo?
Quantos usuários utilizarão o sistema?
Quantos estarão conectados simultaneamente?
Quantas transações ocorrerão por segundo?
Qual tempo de resposta é aceitável?
Quais dados não podem ser perdidos?
Quanto tempo o sistema pode ficar indisponível?
Quais partes precisam de consistência imediata?
O que acontecerá quando um componente falhar?
Quem operará tudo isso às três horas da manhã?
O programador inexperiente olha para o aletiômetro e vê símbolos.
O arquiteto experiente olha para os mesmos símbolos e procura relações.
Da mesma maneira, decorar nomes de tecnologias não transforma ninguém em arquiteto. É necessário compreender os problemas, os limites e os custos ocultos de cada escolha.
Kubernetes não é “melhor” que uma máquina virtual em todas as situações. Kafka não é “melhor” que IBM MQ em todos os fluxos. MongoDB não é uma evolução obrigatória do banco relacional. Microsserviços não representam automaticamente um estágio superior ao monólito.
Tecnologia sem contexto é apenas um símbolo sem interpretação.
2. O primeiro mundo: servidor, monólito e SQL
A caricatura do System Design antigo apresenta uma arquitetura muito simples:
Usuário
↓
Balanceador
↓
Aplicação monolítica
↓
Banco SQL
Essa organização foi — e continua sendo — suficiente para uma enorme quantidade de sistemas.
Em um monólito, os módulos da aplicação são construídos e implantados como uma unidade. Cadastro, pedidos, pagamentos, estoque e relatórios podem estar dentro do mesmo executável ou pacote de implantação.
Isso não significa necessariamente que o sistema seja mal projetado.
Um monólito pode ser:
dividido em módulos claros;
coberto por testes automatizados;
implantado por uma pipeline;
executado em várias instâncias;
protegido por um balanceador;
conectado a um banco replicado;
monitorado;
seguro;
rápido;
fácil de compreender.
O problema não é o monólito. O problema é o monólito sem fronteiras internas.
Para o programador COBOL, isso não deveria soar estranho. Um grande sistema COBOL pode ser organizado em:
programas principais;
subprogramas;
copybooks;
módulos de validação;
rotinas de acesso a dados;
componentes batch;
transações CICS;
chamadas a serviços;
filas MQ.
Tudo pode pertencer ao mesmo domínio sem precisar se transformar em cem serviços independentes.
O erro começa quando qualquer programa altera qualquer arquivo, todas as regras são duplicadas e ninguém sabe qual módulo é responsável pela verdade.
Um monólito bem estruturado é como Jordan College: parece uma instituição única vista de fora, mas possui bibliotecas, salões, dormitórios, cozinhas, autoridades e passagens internas com responsabilidades distintas.
Não é necessário transformar cada cômodo em um país soberano.
3. A primeira curiosidade: sistemas antigos nunca foram realmente simples
A ideia de que “antigamente era tudo simples” precisa ser examinada com cuidado.
Muito antes da nuvem, já existiam:
processamento distribuído;
clusters;
replicação;
filas;
escalonamento de workload;
controle de concorrência;
recuperação de falhas;
sistemas transacionais;
alta disponibilidade;
processamento paralelo;
redes complexas;
bancos particionados;
datacenters geograficamente separados.
O ecossistema mainframe já resolvia muitos desses problemas com tecnologias integradas.
| Necessidade | Recurso no universo mainframe |
|---|---|
| Transações online | CICS ou IMS |
| Banco relacional | Db2 |
| Mensageria confiável | IBM MQ |
| Segurança centralizada | RACF |
| Gerenciamento de carga | WLM |
| Processamento assíncrono | JES e batch |
| Alta disponibilidade | Parallel Sysplex |
| Recuperação geográfica | GDPS |
| Telemetria operacional | SMF, RMF e monitores |
| Integridade transacional | Commit, rollback e logs |
A grande diferença é que parte dessa complexidade ficava escondida dentro de plataformas cuidadosamente integradas.
No mundo cloud-native, a empresa frequentemente monta sua própria plataforma escolhendo componentes separados.
É como se o mainframe entregasse uma grande cidade fortificada, enquanto o mundo distribuído entregasse madeira, pedras, ferramentas, cinquenta projetos open source e um vídeo de vinte minutos chamado “Construa sua cidade em produção sem downtime”.
Ambos podem produzir cidades magníficas.
Mas, no segundo caso, alguém precisa saber construir pontes, muralhas, esgotos e saídas de emergência.
4. A Faca Sutil dos microsserviços
Microsserviços dividem uma aplicação em serviços menores e independentes.
Uma loja digital poderia ser separada em:
serviço de clientes;
serviço de produtos;
serviço de pedidos;
serviço de estoque;
serviço de pagamentos;
serviço de entregas;
serviço de notificações.
Em teoria, cada serviço pode ser desenvolvido, implantado e escalado separadamente. Uma equipe altera pagamentos sem precisar republicar todo o sistema.
Parece maravilhoso.
E pode ser.
Mas a Faca Sutil possui dois lados.
Dentro de um monólito, registrar um pedido poderia acontecer numa única transação:
BEGIN;
INSERT INTO PEDIDO ...;
UPDATE ESTOQUE ...;
INSERT INTO PAGAMENTO ...;
INSERT INTO ENTREGA ...;
COMMIT;
Se algo falhar, executamos ROLLBACK.
Agora imagine que cada tabela pertence a um serviço e a um banco diferente.
O serviço de pedidos grava o pedido. O estoque reserva o produto. O pagamento autoriza o cartão. Entretanto, o serviço de entrega está indisponível.
O que devemos fazer?
Cancelar o pedido?
Liberar o estoque?
Estornar o pagamento?
Tentar a entrega novamente?
Aguardar numa fila?
Marcar a operação como incompleta?
Quem coordena tudo?
Como o suporte descobre o estado verdadeiro?
A transação local simples foi transformada num fluxo distribuído.
Podemos usar uma saga, na qual cada etapa possui uma ação compensatória:
Criar pedido
↓
Reservar estoque
↓
Autorizar pagamento
↓
Criar entrega
Se a criação da entrega falhar:
Cancelar autorização
↓
Liberar estoque
↓
Cancelar pedido
Porém, compensar não é voltar no tempo.
Se um e-mail de confirmação já foi enviado, não conseguimos “desenviá-lo”. Se o pagamento foi registrado numa rede externa, o estorno pode demorar. Se o último produto foi liberado, outro cliente pode comprá-lo antes da repetição.
Ao separar os serviços, não eliminamos a complexidade. Nós a transportamos para a rede.
Esse é um dos grandes easter eggs da arquitetura distribuída: toda porta aberta entre dois mundos cria também uma fronteira que precisa ser vigiada.
5. Os daemons e as responsabilidades dos serviços
Em His Dark Materials, cada pessoa possui um daemon, uma manifestação externa ligada à sua natureza. A distância entre ambos possui consequências.
Uma aplicação também possui extensões que revelam sua natureza:
banco de dados;
cache;
fila;
métricas;
logs;
certificados;
contratos de API;
arquivos de configuração;
políticas de segurança.
O erro é tratar esses componentes como criaturas independentes que podem ser abandonadas no ambiente.
Um microsserviço não é apenas seu código. Ele inclui tudo o que é necessário para que funcione e seja operado:
proprietário responsável;
pipeline de implantação;
banco ou armazenamento;
monitoramento;
alertas;
documentação;
política de backup;
estratégia de recuperação;
controle de versão da API;
tratamento de falhas;
limites de capacidade.
Se uma equipe cria quarenta serviços, criou também quarenta conjuntos de responsabilidades.
A pergunta não é apenas “conseguimos desenvolver?”.
É:
“Conseguimos viver com eles?”
6. Docker e Kubernetes: a armadura de Iorek Byrnison
Docker empacota a aplicação com suas dependências num container. Isso ajuda a reduzir o clássico incidente:
“Na minha máquina funciona.”
O container oferece um ambiente reproduzível. A mesma imagem pode ser executada no notebook, no teste e na produção, respeitadas as diferenças de configuração.
Mas containers precisam ser:
distribuídos;
iniciados;
reiniciados;
atualizados;
conectados;
monitorados;
limitados em CPU e memória;
protegidos;
substituídos quando falham.
É aí que Kubernetes entra.
Kubernetes funciona como uma grande estrutura de orquestração. Ele agenda containers, monitora sua execução, mantém o número desejado de réplicas e coordena atualizações.
Mas Kubernetes é uma armadura, não um urso.
A armadura de Iorek Byrnison amplia sua proteção, porém não substitui sua inteligência, experiência ou vontade. Da mesma maneira, Kubernetes não transforma automaticamente uma aplicação ruim em aplicação resiliente.
Ele pode:
reiniciar rapidamente um programa defeituoso;
criar vinte cópias de um serviço que sobrecarrega o banco;
distribuir uma configuração incorreta para o cluster inteiro;
declarar um container “vivo” enquanto o negócio está paralisado;
aumentar custos ao escalar pelo indicador errado.
Há uma diferença essencial entre:
O processo responde à verificação técnica.
e:
O cliente consegue concluir uma compra corretamente.
O primeiro é um teste de vitalidade.
O segundo exige compreender a saúde do negócio.
Dica do velho urso: se sua empresa possui duas aplicações simples, quatro desenvolvedores e nenhuma equipe de plataforma, talvez uma máquina virtual bem automatizada ou um serviço gerenciado seja mais apropriado que um cluster Kubernetes.
Não construa uma fortaleza no Ártico para guardar uma bicicleta.
7. Bancos de dados: diferentes mundos não obedecem às mesmas leis
PostgreSQL, MongoDB, Cassandra, Redis e Elasticsearch aparecem frequentemente no mesmo diagrama, como se uma arquitetura moderna precisasse coletar todos eles.
Não precisa.
PostgreSQL
É uma excelente escolha geral para sistemas que precisam de:
transações;
integridade;
relacionamentos;
SQL;
consultas variadas;
consistência.
Para enorme quantidade de projetos, começar com um banco relacional continua sendo sensato.
MongoDB
Armazena documentos e pode ser adequado quando os dados são naturalmente tratados como agregados, com estruturas flexíveis.
Mas “flexível” não significa “sem regra”. Se o banco não impõe parte do esquema, a aplicação precisa fazê-lo.
Cassandra
Foi criada para grande distribuição, alta disponibilidade e volumes expressivos de escrita. Sua modelagem começa pelas consultas que serão realizadas.
Não é um PostgreSQL com logotipo diferente.
Redis
Mantém estruturas rápidas em memória e é excelente para:
cache;
sessões;
contadores;
informações temporárias;
limitação de taxa;
coordenação simples.
Entretanto, velocidade não transforma automaticamente Redis no lugar correto para guardar a verdade financeira.
Elasticsearch
É poderoso para pesquisa textual, indexação e análise. Pode ser fantástico como mecanismo de busca e perigoso quando tratado descuidadamente como banco transacional principal.
Cada banco é um mundo com leis físicas diferentes.
A pergunta correta não é “qual está na moda?”, mas:
Como os dados serão consultados?
Precisamos de transações?
Qual volume será escrito?
Podemos tolerar dados temporariamente desatualizados?
Como faremos backup?
Quanto custará restaurar?
Nossa equipe sabe operar esse produto?
Backup não é o arquivo que o job afirma ter produzido.
Backup é aquilo que já demonstramos ser capaz de restaurar.
8. Redis e o Pó do cache
Cache guarda temporariamente dados utilizados com frequência.
Se milhares de pessoas consultam o mesmo produto, talvez não seja necessário buscar a informação no banco todas as vezes. Podemos armazená-la em Redis, numa CDN, no navegador ou na memória da aplicação.
Isso melhora o desempenho e reduz a carga.
Mas o cache, como o misterioso Pó, parece simples até começarmos a observar seu comportamento.
Quando o preço muda, como removemos a versão antiga?
Podemos utilizar:
prazo de expiração;
invalidação explícita;
atualização por evento;
política de escrita simultânea;
carregamento sob demanda.
Suponha que um produto custe R$100 e permaneça no cache durante uma hora. O banco é atualizado para R$80, mas o cache continua exibindo R$100.
O sistema está rápido.
E errado.
Em outro cenário, a promoção termina, mas o cache continua mostrando R$80. Agora o sistema está rápido, errado e juridicamente interessante.
Cache não é apenas desempenho. É uma negociação sobre por quanto tempo aceitamos que uma cópia fique desatualizada.
9. Kafka, RabbitMQ e as mensagens entre os mundos
Mensageria permite desacoplar produtores e consumidores.
O programa que produz uma informação não precisa esperar que todos os interessados terminem seu trabalho.
RabbitMQ
Funciona muito bem para:
filas de tarefas;
roteamento;
distribuição de trabalho;
confirmação de consumo;
entrega de mensagens.
Kafka
Funciona como um log distribuído e durável. Os eventos permanecem registrados por determinado período, permitindo que diferentes consumidores leiam e releiam o histórico.
Um evento chamado:
PAGAMENTO_AUTORIZADO
pode interessar a:
contabilidade;
antifraude;
programa de fidelidade;
notificações;
relatórios;
auditoria.
O produtor publica uma vez. Cada consumidor avança em seu próprio ritmo.
Mas surgem perguntas:
As mensagens precisam manter ordem?
Qual será a chave de particionamento?
O que acontecerá se o consumidor processar duas vezes?
Como mudaremos o formato do evento?
Quanto tempo o histórico ficará armazenado?
Como reprocessaremos milhões de eventos?
O que faremos com uma mensagem que sempre provoca erro?
Para um programador COBOL, IBM MQ oferece uma ponte conceitual importante. Colocar uma mensagem numa fila dentro da mesma unidade de trabalho permite coordenar banco e mensageria com garantias transacionais robustas.
O nome das ferramentas muda. A pergunta permanece:
“Como garantir que o trabalho não desapareça e não seja executado incorretamente duas vezes?”
10. O espectro do retry
Imagine que o sistema envie uma solicitação para cobrar R$500.
O serviço de pagamentos executa a cobrança, mas sua resposta se perde na rede.
O programa chamador recebe timeout.
Ele não sabe se o pagamento falhou. Sabe apenas que não recebeu uma resposta no prazo.
Igor decide tentar novamente.
O cliente é cobrado duas vezes.
Esse incidente ensina uma diferença vital:
Não recebi confirmação.
não significa:
A operação não aconteceu.
Operações críticas precisam ser idempotentes. Isso significa que repetir a mesma solicitação não deve repetir seu efeito.
Uma solução é enviar uma chave única:
IDEMPOTENCY-KEY: PEDIDO-2026-000184
O serviço verifica se essa operação já foi processada. Se já foi, retorna o resultado anterior sem cobrar novamente.
Retries também precisam de:
limite;
intervalo crescente;
jitter;
timeout total;
circuit breaker;
fila de exceção;
reconciliação.
Sem controle, retries viram espectros: quanto mais o sistema sofre, mais requisições retornam para assombrá-lo.
11. Consistência: uma verdade pode chegar atrasada?
Nem todos os dados precisam estar atualizados no mesmo instante.
Uma contagem de visualizações pode aparecer alguns segundos depois. Um ranking pode ser recalculado a cada minuto.
Mas alguns dados exigem decisão imediata:
saldo bancário;
limite de crédito;
último assento disponível;
alteração de senha;
autorização de pagamento;
concessão de permissão;
estoque de um item único.
Se duas pessoas tentarem comprar o último ingresso, o sistema precisa impedir que ambas se tornem proprietárias do mesmo assento.
Isso é consistência forte.
Já a consistência eventual aceita que diferentes cópias se alinhem depois de algum tempo.
O erro está nos extremos:
exigir consistência forte para tudo, sacrificando desempenho e disponibilidade;
aceitar consistência eventual onde o negócio exige uma única verdade imediata.
No mundo distribuído, às vezes dois observadores enxergam estados diferentes. A arquitetura precisa determinar quando isso é aceitável e quando representa um ABEND do negócio.
12. Observabilidade: o aletiômetro de produção
Num monólito, seguir uma operação costuma ser relativamente direto.
Num ambiente distribuído, uma requisição pode atravessar:
API Gateway
↓
Serviço de Pedidos
↓
Serviço de Clientes
↓
Serviço de Estoque
↓
Serviço de Pagamentos
↓
Antifraude externo
Se a resposta demorar oito segundos, onde está o problema?
Pode ser:
DNS;
rede;
certificado;
pool de conexões;
banco;
fila;
retry;
lock;
serviço externo;
falta de CPU;
pausa de garbage collection.
Por isso precisamos de observabilidade.
Métricas
Mostram números ao longo do tempo:
CPU;
memória;
latência;
erros;
filas;
transações por segundo.
Logs
Registram eventos específicos:
pedido recebido;
pagamento negado;
exceção;
timeout;
usuário autenticado.
Traces
Acompanham uma mesma requisição através de vários serviços.
Perfis
Mostram onde o programa consome CPU, memória ou tempo.
Prometheus coleta métricas. Grafana as apresenta. Ferramentas de tracing acompanham operações distribuídas.
Mas uma parede com cinquenta dashboards não significa que alguém compreenda o sistema.
Um bom painel responde a perguntas operacionais. Um bom alerta exige ação. Um log útil contém contexto suficiente para investigação.
O aletiômetro de produção só funciona quando sabemos formular a pergunta.
13. Sharding: cortar o banco com a Faca Sutil
Sharding divide os dados entre servidores.
Por exemplo:
Clientes A–F → Shard 1
Clientes G–M → Shard 2
Clientes N–Z → Shard 3
Ou:
SHARD = HASH(CLIENTE-ID) MOD 4
Isso pode permitir que o sistema armazene e processe mais dados do que um único servidor comportaria.
Mas surgem novos desafios:
consultas entre shards;
transações distribuídas;
rebalanceamento;
clientes concentrados num único shard;
relatórios globais;
restauração;
mudança da quantidade de shards.
Antes de aplicar sharding, verifique:
As consultas possuem índices corretos?
Existem leituras desnecessárias?
Dados históricos podem ser arquivados?
O banco pode crescer verticalmente?
Réplicas de leitura ajudariam?
Cache reduziria a pressão?
Particionamento interno seria suficiente?
O gargalo foi realmente medido?
Sharding prematuro é usar a Faca Sutil para abrir uma passagem antes de saber o que existe do outro lado.
14. Auto scaling e o exército que chega tarde
Auto scaling cria ou remove instâncias conforme a carga.
Parece simples:
CPU alta → criar servidores
CPU baixa → remover servidores
Entretanto, a CPU talvez não represente o problema real.
Um consumidor pode ter CPU baixa e milhões de mensagens atrasadas. Uma aplicação pode aumentar para cinquenta réplicas e criar dez mil conexões contra o mesmo banco.
A camada da aplicação cresce, mas o banco continua único.
O gargalo apenas muda de endereço.
Métricas melhores podem incluir:
tamanho da fila;
atraso do consumidor;
requisições por segundo;
latência;
número de workers ocupados;
conexões disponíveis;
tempo restante para cumprir um SLA.
Escalar também leva tempo. Se uma instância demora cinco minutos para inicializar, talvez chegue depois do pico.
Auto scaling não cria capacidade infinita. Ele administra capacidade disponível dentro de limites técnicos e financeiros.
15. Disponibilidade e o preço dos noves
Dizer “o sistema precisa ficar sempre disponível” é fácil.
Transformar isso num requisito mensurável é mais difícil.
Aproximadamente:
| Disponibilidade | Indisponibilidade mensal permitida |
|---|---|
| 99% | 7 horas e 18 minutos |
| 99,9% | 43 minutos |
| 99,99% | 4 minutos e 23 segundos |
| 99,999% | 26 segundos |
Cada nove adicional exige investimentos em:
redundância;
replicação;
automação;
testes;
failover;
observabilidade;
pessoas;
recuperação;
eliminação de pontos únicos de falha.
Duas instâncias não garantem alta disponibilidade se ambas dependem:
do mesmo banco;
da mesma região;
do mesmo provedor;
do mesmo certificado;
da mesma configuração defeituosa.
Dois mundos podem cair juntos quando a mesma autoridade controla os dois.
Eis outro easter egg do Magisterium: centralizar poder pode simplificar a administração, mas também amplia o impacto de uma decisão errada.
16. Passo a passo do jovem padawan COBOL
Ao receber um novo projeto, não comece desenhando trinta caixas.
Passo 1 — Entenda o negócio
Descubra:
quem usa;
qual problema resolve;
quais operações são críticas;
quanto custa uma falha;
quais leis e auditorias se aplicam.
Passo 2 — Estime a carga
Calcule:
usuários ativos;
simultaneidade;
transações por segundo;
picos;
tamanho dos dados;
crescimento.
Passo 3 — Classifique os dados
Pergunte:
Qual é a fonte da verdade?
O que exige transação?
O que pode ser cacheado?
O que pode ficar temporariamente desatualizado?
Por quanto tempo deve ser preservado?
Passo 4 — Desenhe a solução mínima
Comece, se possível, com:
aplicação modular;
banco relacional;
balanceamento;
armazenamento de objetos;
backup;
monitoramento.
Passo 5 — Identifique gargalos reais
Meça antes de otimizar:
CPU;
memória;
I/O;
locks;
consultas lentas;
conexões;
filas;
latência externa.
Passo 6 — Adicione componentes por evidência
Use cache quando houver leituras repetidas.
Use fila quando o trabalho puder ser assíncrono.
Extraia um microsserviço quando houver fronteira clara e necessidade de independência.
Use Kubernetes quando o volume de workloads justificar uma plataforma.
Aplique sharding quando um banco corretamente otimizado realmente atingir seus limites.
Passo 7 — Projete a falha
Para cada componente, pergunte:
“O que acontece quando ele para?”
Depois pergunte:
“Como descobriremos?”
E finalmente:
“Como recuperaremos?”
Passo 8 — Teste a recuperação
Restaure backups.
Simule indisponibilidade.
Valide timeouts.
Interrompa consumidores.
Teste mensagens duplicadas.
Confirme que os procedimentos funcionam sem depender da memória de Igor.
Passo 9 — Documente decisões
Registre:
contexto;
alternativas;
decisão;
motivos;
riscos;
momento de revisão.
Passo 10 — Preserve o direito de simplificar
Arquitetura também é remoção.
Se um componente deixou de justificar seu custo, aposente-o.
17. Curiosidades escondidas entre os mundos
“Daemon” já existia na computação
Em sistemas Unix, um daemon é um processo executado em segundo plano, frequentemente prestando algum serviço. O termo ganhou uso computacional muito antes da série televisiva e possui raízes conceituais distintas dos companheiros animais de Pullman.
Portanto, se o sysadmin disser que “o daemon morreu”, não procure um animal ferido no corredor. Consulte o log.
Muitos conceitos modernos são antigos com novas interfaces
Filas, isolamento, escalonamento, replicação, controle de acesso e telemetria não nasceram na era dos containers.
A inovação frequentemente está na maneira como esses recursos são empacotados, automatizados, distribuídos e consumidos.
O monólito pode escalar horizontalmente
Monólito não significa servidor único. Se a aplicação for adequadamente projetada, múltiplas instâncias podem atender usuários através de um balanceador.
A rede sempre pode falhar
Dentro do mesmo processo, uma chamada de função é relativamente previsível. Entre serviços, precisamos considerar:
latência;
perda;
duplicação;
timeout;
indisponibilidade;
respostas fora de ordem.
Toda chamada remota é uma aposta controlada.
“Exatamente uma vez” precisa de contexto
Sistemas reais costumam combinar entrega, persistência e idempotência para produzir o efeito de negócio desejado.
Confiar apenas num slogan de “exactly once” é perigoso. O mundo externo — cartão, e-mail, transportadora — talvez não participe da mesma garantia.
Epílogo — A autoridade tentou proibir a simplicidade
No fim da viagem, Lyra Bellacosa chega à sala principal da arquitetura.
Sobre a mesa estão:
API Gateway;
CDN;
Kubernetes;
service mesh;
Redis;
PostgreSQL;
MongoDB;
Cassandra;
Kafka;
RabbitMQ;
gRPC;
WebSockets;
GraphQL;
Elasticsearch;
Terraform;
Prometheus;
Grafana.
Igor sorri e pergunta:
— Instalamos tudo?
O daemon do COBOL observa o diagrama, consulta o aletiômetro e responde:
— Quantos usuários?
Igor hesita:
— Cento e vinte.
— Quantas transações por segundo?
— Talvez três.
— Quantas pessoas na equipe?
— Quatro, contando o estagiário que ainda não recebeu acesso.
O velho urso de armadura fecha a caixa de ferramentas.
A equipe escolhe uma aplicação modular, PostgreSQL, armazenamento de objetos, backup testado, métricas básicas e uma pipeline de implantação.
Não porque desconhece o restante.
Mas porque conhece.
Essa é a diferença entre simplicidade e ignorância. O ignorante usa pouco porque não conhece alternativas. O arquiteto maduro usa pouco porque compreende o preço das alternativas.
System Design não é uma competição para preencher diagramas.
É a disciplina de escolher a quantidade de complexidade que o problema merece — nem menos, deixando riscos escondidos, nem mais, criando uma máquina que ninguém consegue operar.
O programador COBOL iniciante não precisa temer o mundo moderno. Grande parte dele responde às mesmas perguntas que CICS, Db2, MQ, RACF, WLM e os sistemas transacionais enfrentam há décadas:
Como receber trabalho?
Como proteger dados?
Como coordenar operações?
Como suportar falhas?
Como recuperar?
Como provar o que aconteceu?
Como crescer sem destruir o que já funciona?
Mudam os nomes. Mudam as interfaces. Mudam os mapas.
As leis fundamentais continuam reconhecíveis.
E, quando alguém apresentar uma arquitetura com quarenta componentes para resolver um problema que ainda não possui quarenta usuários, segure firmemente sua Bússola de Ouro e faça a pergunta que atravessa todos os mundos:
“Qual problema real justifica cada uma dessas caixas?”
Se ninguém souber responder, não estamos diante de arquitetura.
Estamos diante de uma coleção de tecnologias vestida com uma armadura que não lhe pertence.
Sem comentários:
Enviar um comentário