DBAtlas · Atlas de operações de banco de dados

Arquitetura de referência: camada de dados de microsserviços

Em microsserviços, a decisão mais crítica é a propriedade dos dados: cada serviço deve ser dono dos seus dados (database-per-service) e não deve acessar diretamente as tabelas de outro serviço. Esta árvore percorre passo a passo o antipadrão do banco compartilhado, como obter consistência entre serviços sem transações distribuídas (saga + outbox), a sincronização de dados com CDC e as consultas entre serviços (API composition vs um read model CQRS). O objetivo é manter os serviços realmente independentes e implantáveis separadamente.

Como os serviços são donos dos dados: um banco compartilhado ou um por serviço?

O isolamento dos dados é a espinha dorsal de uma arquitetura de microsserviços. Os serviços usam um único banco compartilhado (uma dependência oculta), cada serviço tem o próprio banco (o padrão correto), ou o verdadeiro desafio é a consistência/as consultas entre serviços? Estabeleça primeiro o estado atual.

  • Todos os serviços usam um único banco compartilhado
  • Cada serviço tem o próprio banco, mas as operações precisam de consistência entre serviços
  • Cada serviço tem o próprio banco, mas são necessárias consultas/relatórios combinados

Como você vai manter consistente um fluxo entre serviços?

Para uma operação que abrange vários serviços (criar pedido → receber pagamento → baixar estoque), uma transação distribuída clássica (2PC) é frágil e não escala. Em vez disso, divida o fluxo em etapas de transação local + evento (saga) e publique os eventos de forma confiável (outbox). Com qual problema você está lidando?

  • Estou tentando manter atômico um fluxo com vários serviços (2PC?)
  • Não consigo tornar consistentes a gravação local e a publicação do evento (dual write)

Como você vai atender a uma consulta que mostra dados de vários serviços?

Depois que os dados são divididos entre serviços, não é possível montar uma tela combinada com um único join. Há duas abordagens principais: chamar as APIs dos serviços envolvidos no momento da requisição e mesclar os resultados (API composition), ou manter um modelo de leitura pré-combinado alimentado por eventos (CQRS). A frequência e a complexidade das consultas determinam a escolha.

  • Join simples e pouco frequente; basta chamar alguns serviços e mesclar
  • Consulta combinada complexa/frequente; é necessário um modelo de leitura pronto

Recomendação: database-per-service (divida o banco compartilhado)

Serviços que compartilham um banco são uma dependência oculta e perigosa: a alteração de schema de um serviço quebra os outros, a propriedade das tabelas fica indefinida e a implantação independente se torna impossível. Cada serviço deve ser dono dos seus dados.

Recomendação: padrão saga (evite transações distribuídas)

Não tente tornar atômica com uma única transação distribuída (2PC) uma operação que abrange vários serviços; o 2PC segura locks e traz fragilidade de ponto único e baixa disponibilidade. Em vez disso, divida o fluxo em etapas que sejam, cada uma, uma transação local no próprio serviço, e desfaça-as com etapas de compensação em caso de falha.

Recomendação: transactional outbox (a armadilha do dual write)

Quando um serviço quer tanto gravar no próprio banco quanto publicar um evento, fazer as duas coisas separadamente é a armadilha do 'dual write': se uma tiver sucesso e a outra falhar, o sistema fica inconsistente. A solução é gravar o evento em uma tabela outbox na MESMA transação local dos dados de negócio e depois publicá-lo com um processo separado.

Recomendação: API composition (combinar no momento do request)

Onde são necessários dados combinados, o chamador (ex.: um gateway/BFF) chama as APIs dos serviços relevantes e combina os resultados em memória. É a solução mais simples para joins simples que abrangem poucos serviços; nenhuma cópia extra de dados é mantida.

Recomendação: read model CQRS (alimentado por eventos)

Para consultas combinadas complexas e frequentes, mantenha um read model pré-combinado e otimizado para consultas (materialized view/cópia desnormalizada), alimentado pelos eventos emitidos pelos serviços. O lado da gravação fica nos serviços; o lado da leitura entrega rapidamente dados prontos a partir de um único lugar.

Abrir no DBAtlas →