MSA환경의 특성
MSA환경에서는 독립된 도메인을 갖고 있으며 DB또한 분리해서 분리해서 사용하게 된다. 그리고 다른 서비스 서버의 DB는 직접적으로 조회하지 않고 요청 또는 이벤트 구독, 별도의 검색 서버를 분리하여 데이터의 무결성, 정합성등을 일치 시킨다.
그렇다면 Entity간의 관계(1:1, 1:M, M:1, M:N)은 어떻게 풀어낼까?
그 방법에 대해선 많은 방법이 있겠지만 내가 생각하는 방식은 두 가지이다. 이 설명을 하기위해 두 개의 서버를 간단히 설명하고자 한다. Movie와 Theater는 1:M의 관계이다. 영화관에서 한개의 영화는 여러개의 상영관이 있다는 것을 관계로 풀어낸 것이다. 생각해보니 Theater는 좌석이라는 뜻으로 의미가 부정확하지만 넘어가 주길 바란다ㅎㅎ
1. Entity를 간접 참조하는 Id값의 저장
@Entity
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@SoftDelete
@SQLRestriction("where is_deleted = false")
public class Theater {
private Long movieId; // movie_fk
}
Theater에는 movieId를 저장하고 필요할때마다 아래와 같이 동기 API를 통해 데이터를 전송하는 것이다.
현재는 영화에 관련된 극장을 저장하는 단계에서 영화 이름을 url 자원에 추가하여 movie의 Id를 받아오는 로직이다.
@Component
@FeignClient(name = "movie-server")
public interface MovieClient {
@GetMapping("/movie/{movieName}")
Long getMovie(@PathVariable String movieName) ;
}
위 방식의 장점
- 도메인 관점에서 원칙을 위배하지 않는 깔끔한 하나의 도메인이된다.
- Movie에 대한 식별자 Id만 있으면 외부 통신을 통해 정보를 가져올 수 있기에 다른 정보가 필요없다.
단점
- 잦은 조회가 필요하다.
- 상영관 등록 : 상영관 등록시 영화관 Id를 함께 저장하기위해 조회가 필요하다.
- 상영관 조회/검색 : 상영관의 영화 제목에 대한 조회또는 검색시 Id를 통해 영화 제목 조회가 필요하다.
2. Movie에 Theater Entity를 생성하고 연관관계 설정하기
Theater에 Movie 엔티티를 생성해서 연관관계를 설정하는 것이다. 이때 모든 필드를 갖고있기 보다 필요한 데이터를 갖고 있는 분신을 하나 만드는 셈이다.
// Theater Entity에 참조키 추가
@ManyToOne
@JoinColumn(name = "movie_copy_entity")
public MovieCopyEntity movieCopyEntity;
참조키를 Theater에 추가하고 연관관계를 설정한다.
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class MovieCopyEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
private String description;
private String genre;
@Column(nullable = false)
private String director;
@Column(nullable = false)
private String actor;
private LocalDateTime releaseDate;
private LocalDateTime closeDate;
}
위 방식의 장점
- 상영관 등록시에만 Movie 서버와 통신하고 MovieInfo로 엔티티 데이터를 저장한다.
- 첫 번째 방식에 비해 네트워크 통신 비용이 적다.
- 엔티티 관계가 한 눈에 보인다.
- 엔티티 그래프 탐색이 가능하다.
단점
- Theater와 Movie엔티티간의 의존성이 발생한다. 도메인 관점에서 바람직하지 못한 방식이라는 생각이 든다.
- 주기적인 데이터 갱신이 필요하다. 유저의 정보가 변경될 경우 캐시 미스, 데이터 정합성 불일치 문제가 발생할 수 있다.
- 이를 해결하기 위한 메세지 큐방식의 이벤트 구독이 필요하다.
그래서 뭐가 더 좋은 방식인가?
위 두 방식에서 관점의 차이는 마이크로 서비스간 통신 비용과 데이터 동기화를 위한 비용중 어느것이 더 저렴한가?로 결정할 수 있다. 이 Trade-off를 잘 생각해보고 해결하면 좋지만 난 튜터님에게 여쭤본 결과 MSA의 독립성 원칙을 지키기 위한 1번을 추천받았다. 모든 방식에는 정답이 없지만 나 또한 구현하고자 하는 아키텍처의 원칙을 최대한 지키려고 하기에 1번 방식으로 개발을 진행하게 되었다.
이 글을 읽는 분들의 생각은 어떠한지 댓글로 알려주면 더 좋겠다 ㅎㅎ
'Spring > Spring Cloud' 카테고리의 다른 글
[MSA - Resilienc4j] CircuitBreaker, fallback 메서드 개발하기 (0) | 2025.02.11 |
---|---|
[MSA - Spring Cloud] Spring Cloud Gateway 개발하기 (1) | 2025.02.08 |
[MSA] 멀티 모듈에서 중복되는 코드를 서브모듈끼리 공유하는 방법 (0) | 2025.02.08 |
[MSA - Spring Cloud] Eureka Client 개발하기(feat. FeignClient) (0) | 2025.02.07 |
[MSA - Spring Cloud] Eureka Server 개발하기(feat. Service Discovery란? 서버/클라이언트 사이드 디스커버리 전략) (0) | 2025.02.07 |