Relacionamento de Entidades entre Microserviços
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 sobreUsuá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
// ...
}
}