ArquiteturaAvançado9 min de leitura5 seções2014, Data aproximada

Microsserviços

Dividir o sistema em serviços pequenos e autônomos, cada um com seu deploy, seu banco e sua escala. Compra autonomia — times e serviços evoluem independentes — e cobra caro: a rede entra no meio de tudo, transações viram sagas, e cada serviço vira um sistema a operar. É uma troca de complexidade de código por complexidade operacional, e só vale quando a autonomia resolve um problema que você de fato tem.

Em 10 segundos

Microsserviços dividem o sistema em serviços autônomos — deploy, banco e escala próprios — que se falam pela rede. O prêmio é autonomia: times e serviços evoluem sem travar uns aos outros. A conta é pesada: a rede (e suas 8 falácias) entra em cada chamada, transações entre serviços viram sagas com consistência eventual, e cada serviço é um sistema a operar. É trocar complexidade de código por complexidade operacional — só vale quando a autonomia resolve um problema real.

Antes de ter nome

A ideia de serviços pequenos e independentes vem da arquitetura orientada a serviços (SOA) dos anos 2000 e da filosofia Unix de programas que fazem uma coisa só.

  • #arquitetura
  • #distribuido
  • #escalabilidade
  • #servicos
  • #autonomia
Analogia

Food trucks × um restaurante grande

Um restaurante grande tem uma cozinha só: um cardápio, um chef coordenando, tudo sob o mesmo teto — simples de operar, difícil de escalar uma parte sem mexer no resto. Uma praça de food trucks é o oposto: cada truck é autônomo, abre e fecha sozinho, tem sua própria fila e pode ser trocado sem afetar os outros. Mas agora alguém precisa coordenar estacionamento, energia, lixo e a praça inteira — a complexidade saiu de dentro da cozinha e foi para o espaço entre os trucks. Microsserviços são a praça: autonomia de cada truck, ao preço de operar a praça.

01Conceito

O que a rede cobra

O erro fundador é achar que microsserviços são 'o monólito, só que em pedaços'. Não são: no momento em que uma chamada de método vira uma chamada de rede, ela herda as 8 falácias — pode falhar, demorar, voltar diferente — e cada uma precisa de timeout, retry e tratamento de erro.

E a transação some. Dentro de um banco, 'cobrar e baixar estoque' é ACID. Entre dois serviços com bancos diferentes, não existe transação compartilhada: vira uma saga, com consistência eventual e ações de compensação para desfazer o que já foi feito.

A regra que dá autonomia de verdade é banco por serviço: cada serviço é dono do seu dado e ninguém acessa as tabelas do outro direto. Sem isso, você tem um 'monólito distribuído' — o pior dos dois mundos: os serviços estão separados fisicamente (com latência de rede e deploys a coordenar) mas acoplados pelos dados (uma mudança de schema quebra vários). A separação física sem a separação de dados só adiciona custo.

É por isso que microsserviços são, antes de tudo, uma decisão organizacional (Lei de Conway): a divisão só entrega o prometido se cada serviço tem um time dono, capaz de fazer deploy sozinho. Dividir o código em dez serviços mantendo um time único que mexe em tudo produz o monólito distribuído. O caminho saudável quase sempre começa por um monólito modular bem fronteirado — as fronteiras de módulo, já testadas dentro do processo, viram as fronteiras de serviço quando (e se) a escala ou a autonomia justificarem a distribuição.

02No mundo real

Como isso aparece na prática

O serviço de checkout que precisava escalar sozinho

Cenário

Numa Black Friday, só o checkout ficava sob carga extrema, mas ele vivia no mesmo monólito que o catálogo e o painel administrativo. Escalar o checkout obrigava a subir réplicas do sistema inteiro, caro e lento.

Como o padrão entra

O checkout foi extraído para um serviço próprio, com deploy e escala independentes, comunicando-se com o resto por eventos. Nos picos, só ele sobe réplicas.

Trade-off: O fluxo de compra passou a atravessar a rede e virou uma saga, com consistência eventual entre checkout, estoque e pagamento. Foi o preço aceito para poder escalar a parte quente sem carregar o resto.

O monólito distribuído que ninguém conseguia deployar

Cenário

Um time dividiu o sistema em oito serviços, mas todos liam e escreviam no mesmo banco compartilhado. Uma mudança de schema quebrava vários serviços de uma vez, e os deploys tinham que ser coordenados como se ainda fosse um monólito — agora com latência de rede.

Como o padrão entra

Cada serviço passou a ser dono do seu próprio banco, e o acesso a dados de outro serviço virou chamada de API ou evento. As fronteiras de dados foram alinhadas às fronteiras de serviço.

Trade-off: Separar os bancos foi uma migração longa e cara, e o que era um JOIN virou chamada remota. Em troca, os serviços finalmente puderam ser desenvolvidos e implantados de forma independente.

03Cuidado

Onde isto dá errado

  1. Banco compartilhado entre serviços

    Serviços que leem e escrevem nas mesmas tabelas estão acoplados pelo dado: uma mudança de schema quebra vários, e os deploys voltam a precisar de coordenação. É o monólito distribuído — custo de rede sem a autonomia.

  2. Dividir cedo demais, com fronteiras incertas

    No início, as fronteiras de domínio ainda estão se descobrindo. Congelá-las em serviços (com rede e banco separados) torna mover uma fronteira caríssimo — o que num monólito modular seria uma refatoração vira uma migração distribuída.

  3. Ignorar a rede entre os serviços

    Tratar chamada remota como local — sem timeout, sem retry, sem tratar falha parcial — faz o sistema desmoronar no primeiro soluço de rede. As 8 falácias não são opcionais quando há rede no meio.

04Implementação

Autonomia com a rede no meio

// Microsservicos: cada servico e autonomo — proprio deploy, proprio
// banco, propria escala. Eles se falam pela REDE, nao por chamada local.

// Servico de Pedidos NAO acessa a tabela de Estoque direto.
// Ele pede, pela rede, ao servico dono daquele dado:
const estoque = await fetch("http://estoque/itens/42").then((r) => r.json());
//              ^^^^^ e aqui entram TODAS as 8 falacias da rede:
//                    pode falhar, demorar, voltar diferente.

// E a transacao que cruza servicos perde o ACID:
// "cobrar + baixar estoque" nao cabe numa transacao de banco unica.
// Vira uma SAGA: cada passo commita local, e uma falha compensa os anteriores.

// A autonomia (deploy e escala independentes) e o premio.
// A rede no meio e a consistencia eventual sao a conta.
05Decisão

Quando usar × quando evitar

Use quando

3
  • Quando vários times precisam entregar sem travar uns aos outros.
  • Quando partes do sistema têm perfis de escala muito diferentes.
  • Quando as fronteiras de domínio já estão claras e estáveis.

Evite quando

2
  • No início de um produto, com time pequeno e fronteiras incertas.
  • Quando um monólito modular ainda resolve.

Testar o que ficou

3 armadilhas de Microsserviços viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.

Onde isto aparece de verdade

Você já usa isto, talvez sem saber o nome.

  • Netflix, Amazon, UberAs arquiteturas de referência que popularizaram serviços pequenos e independentes, cada um com seu deploy e seu banco.
  • um repositório e deploy por serviçoCada serviço com seu próprio ciclo de vida — build, deploy e escala independentes — é a marca operacional do estilo.
  • banco por serviçoCada serviço dono do seu banco, sem outro acessando as tabelas dele direto, é o que dá a autonomia e cobra a consistência eventual.

O padrão em uma linha

Sem nome de domínio, sem cerimônia. Só a ideia.

// Deploy e banco por serviço — fronteira física.
// pedido-svc e estoque-svc não compartilham tabela.

O que ele cobra

3 saltos a mais entre a chamada e o efeito.

  • Cada serviço vira um sistema a operar: deploy, banco, monitoramento, alerta e plantão próprios
  • Uma transação que atravessa serviços perde o ACID e vira saga, com consistência eventual e compensação

Não vale se: o sistema é pequeno e o time é um só — a complexidade distribuída custa muito mais do que a autonomia que ela compra.

Costuma ser confundido com

Onde isto aparece

Continue por aqui