서론
멀티 모듈 프로젝트는 쉽게 말해, 하나의 큰 프로젝트 아래에 여러 기능 혹은 프로젝트를 모듈화하여 관리하는 방식을 말합니다. 각 회사마다 다르겠지만, 대부분의 회사에서는 여러 서비스들을 개발 및 운영하고, 같은 기능(인증 및 인가 등)이나 같은 형식의 데이터베이스 엔티티를 사용하다 보니 회사 규모가 커지면 커질수록 더 많은 리포지토리가 생겨나고, 같은 코드와 같은 기능들이 중복되기 시작합니다.
저의 경우에는 동시다발적으로 진행되는 프로젝트 및 유지보수 운영 때문에 IDE에 열려있는 프로젝트는 점점 많아지고 개발자들 간의 소통 또한 어려워졌으며, 코드 컨벤션(Code Convention)들도 어긋나게 되는 상황이 발생하였습니다. 이를 해결하기 위해 같은 기능을 담당하는 코드들을 통합하는 기회를 만들 겸 멀티 모듈 프로젝트를 시작하게 되었습니다.
1. 모듈 (Module)
우리는 학생 시절 모듈의 높은 응집도와 낮은 결합도가 좋은 품질의 소프트웨어를 만드는 데 기여한다는 것을 배웠습니다. 다들 한 번쯤 들어봤을 "우논시절통순기 내공외제스자".
뭣도 모르는 시절에 외웠던 그 단어들이 멀티 모듈 프로젝트를 진행해보며 현실적으로 와닿았습니다. 모듈과 모듈 간의 의존 정도를 얘기하는 결합도와 모듈 내 구성 요소들 간의 연관 정도를 의미하는 응집도. 낮은 결합도와 높은 응집도는 좋은 모듈을 만드는 하나의 마법의 주문과 같았습니다.
멀티 모듈 프로젝트를 진행하며 각 모듈은 이름에 걸맞게 최소한의 기능만 담당하도록 만들고 싶었고, 공통 모듈을 다른 모듈에서 원활하게 사용하기 위해 의존성(dependency)을 적절히 활용하였으며, 비즈니스 로직을 담당하는 모듈끼리는 Spring Cloud OpenFeign을 사용하여 통신하였습니다.
API들의 모든 인증과 인가 처리를 한곳으로 묶기 위해 Spring Cloud Gateway를 사용하였고, 각 모듈들이 실행되어 만들어지는 애플리케이션을 관리하기 위해 Spring Cloud Eureka를 함께 도입하였습니다.
2. 아키텍처 설계
아키텍처 설계는 정말로 어려운 과정입니다. 제가 좋아하는 웹툰 **'화산귀환'**의 주인공 청명은 이렇게 말했습니다. "바닥이 얼마나 튼튼한지에 따라 높은 탑을 쌓을 수 있느냐가 결정되지." 이는 소프트웨어 개발에서도 기본적인 설계의 중요성을 잘 나타냅니다.
부족한 CS 지식으로 만든 설계는 프로젝트 중반에도 개발자들을 곤란하게 만들 수 있다고 생각합니다. 그래서 세밀한 설계가 아니더라도 큰 틀에서의 올바른 설계는 매우 중요하다고 느꼈고, 실제 프로젝트를 진행하기 전에 충분한 학습과 연구에 몰두했습니다.
현재의 아키텍처는 A, B, C, D라는 REST API 프로젝트와 E라는 RabbitMQ 기반의 Notification 프로젝트로 구성되어 있습니다. 각 프로젝트는 Redis와 RDB를 사용하고 있으며, A와 C 프로젝트는 JWT 기반의 인증 및 인가를, B와 D 프로젝트는 세션 기반의 인증 및 인가를 사용하고 있었습니다. 이러한 인증 방식의 일관성 부족은 유지보수와 확장성 측면에서 문제를 일으킬 수 있었습니다.
그래서 저는 인증 및 인가 방식을 통합하기로 결정했습니다. Spring Security와 JWT를 활용하여 Auth 모듈을 구현하고, Spring Cloud Gateway에서 인증과 인가를 처리하기 위한 필터를 적용하였습니다. 이렇게 함으로써 모든 인증 및 인가 로직은 Gateway와 Auth 모듈에서 중앙 집중적으로 관리되며, 토큰의 발행과 검증은 Auth 모듈이 담당하게 됩니다.
또한, 공통적으로 사용되는 Redis를 하나의 Redis 모듈로 분리하여 필요로 하는 모듈에서 의존성으로 포함할 수 있도록 하였습니다. 공통적으로 사용되는 데이터베이스 엔티티나 유틸리티 클래스들은 Core 모듈로 분리하여 재사용성을 높였습니다.
Eureka 서버를 통한 서비스 등록에서는 실제 마이크로서비스로 동작하는 모듈들만 등록하도록 설계하였습니다. 따라서 Core 모듈이나 Redis 모듈처럼 라이브러리 형태로 제공되는 모듈들은 Eureka에 등록하지 않았습니다. 이는 서비스 디스커버리에서 불필요한 혼선을 방지하고, 실제로 통신이 필요한 서비스들만 관리하기 위함입니다.
이러한 아키텍처 설계를 통해 각 모듈의 역할과 책임을 명확히 하고, 공통 기능의 재사용성을 높여 유지보수성과 확장성을 향상시킬 수 있었습니다.
추가로 고려한 사항들:
- 모듈 간 통신 방식: 비즈니스 로직을 담당하는 모듈들 간에는 Spring Cloud OpenFeign을 사용하여 RESTful하게 통신하도록 하였습니다. 이를 통해 모듈 간 결합도를 낮추고 확장성을 높였습니다.
추가로 고려해야 할 사항들 :
- 환경 설정의 일원화: 각 모듈에서 공통적으로 사용되는 설정들은 Spring Cloud Config를 활용하여 중앙에서 관리하도록 하였습니다. 이는 환경 설정의 일관성을 유지하고 변경 사항을 신속하게 반영할 수 있게 합니다.
- 로깅 및 모니터링: 전체 시스템의 상태를 효과적으로 모니터링하기 위해 Spring Boot Actuator와 ELK Stack을 도입하였습니다. 이는 문제 발생 시 신속한 대응을 가능하게 합니다.
결론
학습과 연구를 토대로 하나의 멀티 모듈 프로젝트를 만들어보면서 경험한 내용을 정리 및 복기하기 위해 본 포스팅 시리즈를 기획하고 작성하게 되었습니다. 차근차근 포스팅 해나가며 정리하며 이 지식을 온전히 저의 것으로 만들기 위해 노력할 것 입니다.
'Spring Boot' 카테고리의 다른 글
Spring Batch - 배치의 삭제 로직 성능 최적화 (1) | 2024.11.05 |
---|---|
Spring Boot 기반 다수의 프로젝트를 하나의 Multi Module 프로젝트로 통합하기 (2) - 인증과 인가를 담당하는 Auth Api (0) | 2024.11.01 |
Redis를 활용한 조회수 시스템 최적화와 동시성 이슈 해결 (1) | 2024.10.18 |
Spring Boot에서 발생하는 직렬화 오류 해결 가이드 (0) | 2024.10.08 |
RabbitMQ 활용하기 (8) | 2024.09.30 |