아직 작업중인 내용이 있어서 이후에 내용이 추가됩니다 :)
오늘 한 일
- 실습할 프로젝트 기획
- 모노레포 개설 및 Server, gateway, user(client), auth(client) 애플리케이션 개발
- Spring Cloud Eureka 실습
- Spring Cloud Gateway 실습
작업 내용
실습할 프로젝트 기획
나는 MSA 강의를 듣고 직접 부딪혀보며 MSA환경을 구성하면 어떤 문제들이 생기는가 알아보기 위해 미니 프로젝트를 하나 해보기로 했다.
강사님은 티켓관련 프로젝트로 아래와 같이 형체를 알아 볼수는 없지만 그래도 나만 알아보면 되는? 아키텍처를 설명해주셨고 나는 이를 기반으로 영화 예매 시스템을 하나 만들어보기로 했다.
그렇게 내가 생각한 아키텍처는 아래 사진과 같다.
이 아키텍처가 성공적으로 다 개발이 되다면 그 이후 Config서버로 동적인 환경 설정 또한 도전해보려고 한다.
Eureka 서버가 다른 Client Registry를 소유하며 위치를 동적으로 저장하고 리스트를 제공해준다.
Gateway는 모든 요청을 받아 대신 적절한 서버로 리디렉션 해주는 역할이다. 또한 필터를 통해 유저의 인증역할을 수행한다.
그 외 특별한 점은 Auth서버에서 토큰을 생성하고 발급하며, Error를 수집하고 분석할 수 있는 별도의 서버를 개설해보려 한다는 점이다. Error 인스턴스는 DB, NoSQL, Elastic Search 등 다양한 방식으로 개발이 가능해서 마지막에 좀 더 고민해보고 정하려 한다.
그리고 도메인 및 유즈케이스에 대한 내용을 간단히 기록해봤다. 간단한 미니 프로젝트이기에 ERD나 상세한 문서는 여유가 생긴다면 추가로 만들어보려고 하며, 어떤 도메인이 필요하고 어떤 동작들이 필요할지만 나열해보았다.
모노레포 개설 및 Server, gateway, user(client), auth(client) 애플리케이션 개발
개발하기에 앞서 우선 Github에 이 애플리케이션을 구조를 어떻게 만들어야 좋을까? 하는 고민부터 시작하게 됐다.
이 방식에는 두 가지 방식이 있었다. 모노레포 와 멀티 레포 전략이다.
모노 리포 vs 멀티 리포
두 리포 전략에 대해서는 포스팅을 읽어보기 바라며 나는 모노 리포로 작성하기로 했다! 모든 프로젝트가 한 눈에 보여야 더 편할 것 같다! 물론 그만큼 프로젝트 규모가 작기 때문이기도 하다. 일관성과 무결성을 더 쉽게 유지하는 것이 좋다고 생각했다.
그래서 보다시피 msa-movie-reservation 이라는 리포지터리 하나에 여러 개의 모듈을 관리중이다!
그럼 EurekaServer 부터 어떻게 개설하고, 필요한 개념이 무엇이 있었는지 알아보자.
내용이 너무 길어지는 것들은 별도의 포스팅 링크를 남겨놓으려고 한다.
[Eureka Server 개발 및 Service Discovery 개념, 전략 파헤치기!]
[Eureka Client 개발 및 FiengClient 알아보기]
문제 해결
- JPA 연관관계 맵핑을 MSA환경에서 어떻게 풀어낼 것 인가?
- 두 가지 방법이 있다. 첫 번째 방법은 각 서비스에 연관관계를 가지는 임의의 엔티티를 하나 생성하는 것.
- 만약 User와 Product가 1:M의 관계를 가진다면 User 서비스에 ProductInfo라는 임의의 엔티티를 생성하고 사용하는 것이다.
- 두 번째 방법은 FeignClient를 통해 필요할 때 마다 통신을 보내서 필요한 데이터를 적절한 쿼리를 통해 받아오는 방법이다.
- 이 두 가지 방법은 MSA의 모듈간의 독립성을 흐리게하는 방법이지만 성능을 고려한다면 이게 더 적절한 방법이지 않을까 싶다. 또한 두 번째 방법이 데이터의 정합성에서 조금 더 확실한 측면이 있기에 이 방법을 사용할 것 같다.
- 두 가지 방법이 있다. 첫 번째 방법은 각 서비스에 연관관계를 가지는 임의의 엔티티를 하나 생성하는 것.
- Spring Security를 각 서버에 두고 ContextHolder에 유저 정보를 저장해야 하나?
- 이후 개발할 Gateway에 Filter 기능이 있어 인증 및 인가에 대한 처리를 할 수 있으므로 Security의 필요성이 모호해진다. 또한 Auth Server와 주기적으로 통신하여 유저의 데이터를 최신화해야 문제가 발생하지 않기에 각 서비스 인스턴스에 `Securit ContextHolder`에 유저의 정보를 저장한다 하더라도 무결성 및 정합성에 문제가 발생할 수도 있다. 결론은 개발하는 환경 및 팀원간에 협의를 통하 하나의 방법을 정해야 하고 정답은 없다는 것이다! `Trade-off`에 대해 더 많은 관점으로 논의할 수 있는 지식을 함양하고 있는것이 제일 중요하다고 생각한다.
- exchange 메서드에 넣은 Header가 업데이트 되지 않는 현상
if (accessToken == null || !validateToken(exchange, accessToken)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}else{
return chain.filter(customSeverWebExchange(exchange,getClaims(accessToken)));
}
private boolean validateToken(ServerWebExchange exchange, String token) {
try {
Claims claims = getClaims(token);
customSeverWebExchange(exchange, claims);
return true;
} catch (Exception e) {
log.info(e.getMessage());
return false;
}
}
private static ServerWebExchange customSeverWebExchange(ServerWebExchange exchange, Claims claims) {
ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate()
.header("X-User-Id", claims.get("user_id").toString())
.header("X-Role", claims.get("role").toString())
.build();
exchange = exchange.mutate().request(serverHttpRequest).build();
return exchange;
}
validateToken메서드에서 exchange 매개변수를 통해 추가 헤더를 전달하는 과정에서 제대로 전파가 되지 않는 문제가 발생했다. 수많은 시간 삽질을 통해 반환하는 exchange가 if문 내부 메서드에서만 수행되고 외부 exchange가 업데이트 되지 않는 상태인 걸 발견했다. 그래서 else분기점에 customServerWebExchange가 수행되고 이를 filterchain의 exchage메서드로 반환되도록 수정했더니 데이터가 잘 전파되는 것을 확인했다!
내일 할 일
- Movie(client), Theater(client), Order(client) 각 애플리케이션 개발하고 연결하기
- 서킷브레이커 설정하기
- QueryDSL 적용하여 쿼리 메서드 짜보기
- LoadBalancer를 통해서만 요청이 오갈 수 있도록 설정하기
'TIL' 카테고리의 다른 글
[TIL] MSA 서비스 Resilience4j로 CircuitBreak설정, Fallback 실습 (0) | 2025.02.11 |
---|---|
[TIL] MSA 각 서비스 모듈 자원 공유하기, Movie Service 개발 (0) | 2025.02.08 |
[TIL] JPA 프로젝트 완성 및 배포 (0) | 2025.02.05 |
[국비지원과정20] 자바 - 클래스 메서드와 인스턴스 메서드가 헷갈린다면? (1) | 2023.08.07 |
[국비지원과정19] JVM 구조 (0) | 2023.08.06 |