Pular para conteúdo

Relacionamento de Entidades entre Microserviços

mmd

Introdução

No contexto de engenharia de software e arquitetura de microserviços, a maneira como as entidades se relacionam entre si é crucial para garantir a integridade e a eficiência do sistema. Este documento aborda como gerenciar relacionamentos entre microserviços que utilizam bases de dados separadas, além de discutir o uso de uma única base de dados para múltiplos microserviços e a replicação de dados através de eventos de domínio.

1. Relacionamento de Entidades entre Microserviços

1.1. Identificação por ID Externo

Em um cenário onde os microserviços possuem suas próprias bases de dados, um dos desafios é a necessidade de relacionar entidades que pertencem a serviços distintos. A prática recomendada é utilizar IDs externos. Isso significa que, ao invés de manter uma referência direta a outra entidade (por exemplo, uma chave estrangeira), um microserviço armazenará o ID da entidade de outro microserviço.

Exemplo:

  • Serviço A: Gerencia Usuários
  • Serviço B: Gerencia Ordens

No banco de dados do Serviço B, em vez de ter uma chave estrangeira que referencia diretamente um Usuário do Serviço A, o Serviço B armazena apenas o userId do Usuário. Isso cria um desacoplamento entre os serviços e permite que cada um seja escalável e independente.

1.2. Vantagens

  • Desacoplamento: Os microserviços podem ser alterados ou escalados independentemente.
  • Resiliência: Se um microserviço estiver fora do ar, o outro ainda pode funcionar, desde que tenha a lógica para lidar com a ausência de dados.
  • Facilidade de manutenção: Mudanças em um microserviço não impactam diretamente o outro.

2. Microserviços com a Mesma Base de Dados

2.1. Uso Compartilhado de uma Base de Dados

Em alguns casos, pode ser desejável que múltiplos microserviços acessem a mesma base de dados. Isso pode ser feito quando os microserviços são fortemente acoplados ou quando há um alto custo de manutenção ao dividir a base de dados.

Remapeamento do Domínio como Subdomínio

Quando dois ou mais microserviços usam a mesma base de dados, pode-se considerar a implementação de um subdomínio. O subdomínio é uma parte da lógica de negócios que é agrupada de acordo com um contexto específico. Por exemplo:

  • Serviço A pode ser responsável por gerenciar Usuários
  • Serviço B pode ser responsável por gerenciar Autenticação

Ambos os serviços acessam a mesma base de dados, mas cada um se concentra em um aspecto diferente do domínio.

2.2. Vantagens

  • Consistência de dados: Fácil gerenciamento de dados que precisam ser acessados por múltiplos serviços.
  • Simplicidade: Reduz a complexidade da arquitetura ao evitar a necessidade de comunicação entre serviços para operações simples.

3. Replicação de Dados em Subdomínios

3.1. Mapeamento de Entidades em Subdomínios

Quando temos a mesma entidade mapeada em diferentes subdomínios, a replicação de dados é uma questão importante. Para garantir que as informações sejam consistentes entre os subdomínios, podemos utilizar o conceito de eventos de domínio.

Exemplo de Replicação:

  • Serviço A: Gerencia Usuários
  • Serviço B: Gerencia Notificações, que também precisa de informações sobre Usuários.

Quando um Usuário é criado ou atualizado no Serviço A, ele pode publicar um evento de domínio, como UserCreated ou UserUpdated. O Serviço B pode escutar esses eventos e atualizar sua própria base de dados com as informações necessárias.

3.2. Vantagens da Replicação via Eventos de Domínio

  • Desacoplamento: Os serviços não precisam saber um do outro; apenas escutam eventos.
  • Escalabilidade: Cada serviço pode escalar de maneira independente.
  • Consistência eventual: Os dados são mantidos atualizados sem necessidade de chamadas diretas entre serviços.

Exemplos

Cenário

  • Colaborador: Representa um usuário no sistema.
  • Requisição de Feedback: Um pedido feito por um colaborador para receber feedback de outro colaborador.
  • Serviço A: Gerencia os colaboradores.
  • Serviço B: Gerencia as requisições de feedback.

1. Relacionamento de Entidades entre Microserviços

1.1. Identificação por ID Externo

Entidade Colaborador (Serviço A)

@Entity
public class Colaborador {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String nome;
    private String email;

    // Getters e Setters
}

Entidade Requisição de Feedback (Serviço B)

@Entity
public class RequisicaoFeedback {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Long colaboradorId; // ID do colaborador que faz a requisição
    private Long colaboradorFeedbackId; // ID do colaborador que receberá o feedback
    private String mensagem;

    // Getters e Setters
}

1.2. Exemplo de Criação de Requisição de Feedback

@RestController
@RequestMapping("/feedback")
public class RequisicaoFeedbackController {

    @Autowired
    private RequisicaoFeedbackService feedbackService;

    @PostMapping("/request")
    public ResponseEntity<RequisicaoFeedback> solicitarFeedback(@RequestBody RequisicaoFeedbackDTO dto) {
        RequisicaoFeedback feedback = feedbackService.solicitarFeedback(dto);
        return ResponseEntity.status(HttpStatus.CREATED).body(feedback);
    }
}

DTO para Requisição de Feedback

public class RequisicaoFeedbackDTO {
    private Long colaboradorId;
    private Long colaboradorFeedbackId;
    private String mensagem;

    // Getters e Setters
}

2. Microserviços com a Mesma Base de Dados

2.1. Uso Compartilhado de Uma Base de Dados

Entidade Colaborador (Serviço A e B)

@Entity
public class Colaborador {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String nome;
    private String email;

    // Getters e Setters
}

Entidade Requisição de Feedback (Serviço B)

@Entity
public class RequisicaoFeedback {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Long colaboradorId; // ID do colaborador que faz a requisição
    private Long colaboradorFeedbackId; // ID do colaborador que receberá o feedback
    private String mensagem;

    // Getters e Setters
}

2.2. Exemplo de Criação de Requisição de Feedback

@RestController
@RequestMapping("/feedback")
public class RequisicaoFeedbackController {

    @Autowired
    private RequisicaoFeedbackService feedbackService;

    @PostMapping("/request")
    public ResponseEntity<RequisicaoFeedback> solicitarFeedback(@RequestBody RequisicaoFeedbackDTO dto) {
        RequisicaoFeedback feedback = feedbackService.solicitarFeedback(dto);
        return ResponseEntity.status(HttpStatus.CREATED).body(feedback);
    }
}

Neste cenário, ambos os serviços (Serviço A e Serviço B) acessam a mesma base de dados. Os colaboradores são gerenciados no mesmo banco, mas a lógica de feedback é isolada no Serviço B.


3. Replicação de Dados em Subdomínios

3.1. Mapeamento de Entidades em Subdomínios

Publicando Evento de Domínio ao Criar Requisição de Feedback

Quando um colaborador solicita feedback, um evento é publicado para informar outros serviços.

public class RequisicaoFeedbackService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public RequisicaoFeedback solicitarFeedback(RequisicaoFeedbackDTO dto) {
        RequisicaoFeedback feedback = new RequisicaoFeedback();
        feedback.setColaboradorId(dto.getColaboradorId());
        feedback.setColaboradorFeedbackId(dto.getColaboradorFeedbackId());
        feedback.setMensagem(dto.getMensagem());

        // Salvar a requisição no banco
        // ...

        // Publicar evento
        eventPublisher.publishEvent(new FeedbackRequestedEvent(feedback));

        return feedback;
    }
}

Evento de Domínio

public class FeedbackRequestedEvent {
    private final RequisicaoFeedback feedback;

    public FeedbackRequestedEvent(RequisicaoFeedback feedback) {
        this.feedback = feedback;
    }

    public RequisicaoFeedback getFeedback() {
        return feedback;
    }
}

3.2. Consumindo o Evento de Domínio

No Serviço B, um listener pode ser implementado para tratar o evento e atualizar a base de dados.

@Component
public class FeedbackRequestedListener {

    @Autowired
    private ColaboradorRepository colaboradorRepository;

    @EventListener
    public void handleFeedbackRequested(FeedbackRequestedEvent event) {
        RequisicaoFeedback feedback = event.getFeedback();
        // Lógica para atualizar ou armazenar dados relacionados ao feedback
        // ...
    }
}