개요
- Spring Boot 멀티 모듈 프로젝트 구성 이유 및 방법들을 해당 문서에 정리한다
목적
- 초기 사이드 프로젝트 설계에서 어떠한 설계로 시작하는 게 가장 적합할지 고찰해 보는 과정을 통해
프로젝트 설계에 대한 시야를 넓히기 위함 - 멀티 모듈 프로젝트 세팅 과정을 정리하면서 신규 프로젝트 구성에 대한 이해도를 높이기 위함
왜 멀티 모듈을 선택했는가?
- 숙박 예약 서비스를 타겟 서비스로 구상하면서 각 API를 구분하여 개별 서버로 분리하는 게 좋겠다는 판단을 하였다
- 여기서 말하는 각 API의 구분은 다음과 같다
- 숙박 예약을 하려는 일반 고객용 API
- 숙박을 제공하는 업체용 API
- 전체적인 시스템을 관리할 관리자 API
- 여기서 말하는 각 API의 구분은 다음과 같다
- 그래서 왜?
사실 API를 구분할 필요 없이 하나의 서버에서 단일 프로세스로 개발을 시작해도 아무런 문제가 없다
따라서 그냥 좋겠다는 판단이 아니라, 구체적인 기준을 두고 장단점을 비교해서 선택한 결과여야한다 - 그러므로 단일 모듈과 멀티 모듈 개념에 대해 먼저 정리해 본다
단일 모듈 (Monolithic) vs 멀티 모듈 (Multi-Module)
💡 먼저 개념을 정리해 보자
✅ 단일 모듈 (Monolithic)
✔ 하나의 Spring Boot 애플리케이션에서 모든 API를 한 곳에서 관리
✔ 일반 고객, 업체, 관리자 API가 하나의 프로세스 안에서 동작
✔ 당연히 하나의 프로젝트(소스 코드)로 관리됨
- 프로젝트 구조
hotel-reservation/
├── src/main/java/com/pablo/hotel/
│ ├── controller/ # 모든 API 컨트롤러 포함
│ ├── service/ # 모든 비즈니스 로직 포함
│ ├── repository/ # 모든 데이터 액세스 로직 포함
- Spring Boot 프로젝트로 초기에 시작하기에 가장 간단한 구조다
- 하나의 프로젝트이며 단일 프로세스가 실행되도록 구성되어 있기 때문에 API 배포도 간단하다
- 소스 코드도 한 곳에서 관리되기 때문에, 코드 재사용성이 가장 높다
- 하지만 단일 프로세스인 만큼 모든 API의 요청을 처리해야 하기 때문에 상대적으로 부하가 더 심할 수밖에 없겠다
- 마찬가지로 단일 프로세스인 만큼 특정 API로 인해 장애가 생기면 모든 서비스에 영향이 갈 수도 있다
✅ 멀티 모듈 (Multi-Module)
✔ 각기 다른 Spring Boot 애플리케이션에서 API를 관리
✔ 즉, 일반 고객, 업체, 관리자 API가 각각 별도의 프로세스로 동작
✔ 그러나 하나의 프로젝트(소스 코드)로 관리되며, 서로 공유하는 로직(코드)이 존재할 수 있음
- 프로젝트 구조
hotel-reservation-platform/
├── common/
├── customer-api/
├── host-api/
├── admin-api/
- 각 모듈별로 별도의 디렉터리 구조를 가져감으로 써, 단일 모듈보다 상대적으로 복잡한 구조다
- 하나의 프로젝트이나 모듈별로 프로세스가 실행되도록 구성되어 있기 때문에,
한 번에 전체 API에 반영해야 되는 이벤트가 발생하면 배포가 복잡해진다 - 각 모듈별로 별도의 디렉터리 구조이나 프로젝트 소스 코드는 한 곳에서 관리되기 때문에,
재사용이 높은 공통 소스 코드를 별도로 관리할 수 있다 - 모듈별로 프로세스가 실행되는 구조이기 때문에, 단일 모듈 구조에 비해 API 요청이 분산되어 부하가 낮아진다
- 마찬가지로 모듈별로 프로세스가 분리되기 때문에,
특정 모듈 API로 인해 장애가 생겨도 다른 모듈 API는 장애가 일어나지 않을 수 있다
즉, 단일 모듈에 비해 장애 격리가 가능하다
📌 단일 모듈 vs 멀티 모듈의 장단점 비교
💡 위에 개념 정리한 내용을 토대로 장단점을 비교해 보자
단일 모듈 (Monolithic) | 멀티 모듈 (Multi-Module) | |
✅ 초기 개발 속도 | 빠름 🚀 | 상대적으로 느림 ⏳ (모듈 구성 필요) |
✅ 배포 편의성 | 하나의 서버만 관리하면 됨 ✅ | 여러 개의 서버를 배포해야 함 ⚠️ |
✅ 성능 확장성 | 단일 서버에 부하 집중 가능 ⚠️ | API 별로 독립적인 확장 가능 🚀 |
✅ 유지보수성 | 하나의 코드베이스로 쉽게 유지보수 가능 | API 별로 분리되어 있어 코드 변경이 명확 |
✅ 장애 격리 (Fail Isolation) | 한 API 장애가 다른 API에도 영향 ⚠️ | 각 API가 독립적으로 동작 🚀 |
✅ 팀 분리 가능 여부 | 하나의 팀에서 관리 | API 별로 개별 팀 운영 가능 ✅ |
✅ 공통 모듈 활용 | 코드 재사용 가능 ✅ | 공통 모듈(common)을 따로 만들어 활용 ✅ |
멀티 모듈을 선택한 이유 (이번 사이드 프로젝트에)
- 위와 같이 단일 모듈과 멀티 모듈에 대해 개념과 장단점을 알아보았다
- 그런데 과연 이제 막 설계를 시작하는 서비스 구조에서 멀티 모듈을 선택하는데 큰 의미가 있는 장점이 맞는가?
- 솔직히 필자가 볼 때, 이제 막 설계를 시작하는 서비스 구조에서는 장점보다 단점이 더 큰 것이라 느껴진다
WHY?
초기 개발 속도가 느려질 수 있고, 배포가 복잡해지는 게 가장 큰 단점이다
상대적으로 서버 부하가 덜하겠다는 장점은 부하가 그만큼 심각해야 의미가 있을 것이고,
팀 분리 가능 여부도 아직 API 별로 팀 운영을 할 수도 있겠다는 염두를 할 때가 아닐 것 같다
따라서 이제 막 서비스를 구상하려는 단계에서 가장 적합한 이유를 생각해 보자
- 솔직히 필자가 볼 때, 이제 막 설계를 시작하는 서비스 구조에서는 장점보다 단점이 더 큰 것이라 느껴진다
(현시점) 가장 주된 이유
- 필자가 이제 막 서비스를 구상하려는 단계에서 멀티 모듈을 선택한 가장 주된 이유는 다음과 같다
(물론 정답이 아닐 수 있다, 어디까지나 현시점의 개인의 생각이다)
✅ 주된 이유 1. API 별 인증 및 보안 정책을 다르게 적용 가능
- API 유형 별로 '사용 대상'이 달라지기 때문에 '사용 대상' 별로 다른 인증 체계를 가져가야 한다
예를 들어, 아래와 같이 보안 체계를 가져갈 수 있다- customer-api: 고객 API는 OAuth, JWT 기반 인증을 적용해야 함
- admin-api: 관리자는 특정 IP 대역에서만 접근 가능하도록 제한하는 것이 보안상 유리
- host-api: 숙박 업체는 별도의 API Key 인증 방식이 필요할 수도 있음
💡 즉, 단일 모듈에서 모든 API를 한 곳에서 운영하면 멀티 모듈에 비해 서로 다른 보안 정책을 적용하기 어렵다
👉 API 별로 인증 및 접근 제어를 다르게 설정해야 하는데, 이를 유연하게 적용하기 위해 API를 분리하는 것이 필요하다
✅ 주된 이유 2. API 트래픽 분산 및 부하 관리
- 아무리 서비스 구상 초기 단계라 할지라도, '사용 대상'에 따라 API 요청 횟수가 다를 것이란 예상은 할 수 있다
- 예를 들어, 아무리 생각해도 업체 회원 수보다는, 일반 고객 수가 훨씬 많을 것으로 예상할 수 있고,
- 또, 상대적으로 관리자 수는 업체 회원 수 보다는 훨씬 더 적을 것이라 예상할 수 있다
- 따라서 '사용 대상'을 기준으로 분리한 서버들은 특성을 생각하여 부하를 예상하며 운용하기가 수월해진다
- admin 서버는 저사양으로 운용해서 비용을 아낀다던지 말이다
- 하지만 단일 애플리케이션으로 모든 API 요청을 처리하면, 트래픽이 한 곳으로 집중된다
📌 예시:
✔ customer-api: 많은 요청이 들어올 수 있음 (고객 조회, 예약 등)
✔ admin-api: 상대적으로 요청이 적음 (관리자 조회, 승인 등)
✔ host-api: 주기적인 데이터 업데이트는 많을 수 있지만 실시간 트래픽은 낮음
👉 즉, 현재로선 "부하가 엄청 심하지 않다"는 점을 고려하더라도, 향후 확장성을 위해 API 분리는 좋은 선택이다
✅ 주된 이유 3. 독립적인 배포 및 운영 가능
- 마찬가지로 서비스 구상 초기 단계라 할지라도, '사용 대상'별로 업데이트가 자주 일어나는 API를 예상할 수 있다
- 단일 모듈에서는 모든 API가 한 번에 배포되어야 한다
- 하지만 API를 분리하면, 각 API의 운영 방식에 맞춰 개별 배포가 가능하다
📌 예시:
✔ customer-api는 자주 업데이트될 수 있지만, admin-api는 상대적으로 변경이 적음
✔ host-api는 주기적인 데이터 동기화 작업이 많아 배포 전략이 다를 수 있음
💡 즉, 각 API의 운영 방식에 맞게 독립적인 배포 전략을 적용할 수 있다는 점도 큰 장점될 수 있다
👉 즉, "초기 단계라서 구조가 복잡하지 않다"는 점을 고려하더라도,
API별 운영 방식이 다르다는 점이 충분한 이유가 된다
(향후에) 좋은 장점
✅ 1. 향후 API 확장 가능성을 고려 (확장성)
- 단일 프로세스에서는 트래픽이 증가하면 서버 전체를 스케일링해야 하지만,
멀티 모듈 구조에서는 필요한 API만 독립적으로 확장 가능하다
(예: 고객 API만 트래픽 폭증 시, customer-api만 확장 가능)
✅ 2. 서비스 장애 격리 가능 (Fail Isolation)
- 단일 프로세스에서는 하나의 API에서 장애가 발생하면, 모든 API가 영향을 받을 수 있다
- 반면, 멀티 모듈 구조에서는 각 API가 독립적으로 실행되므로, 장애가 격리된다
(예: admin-api 장애 발생 시, customer-api는 정상 작동)
✅ 3. 유지보수성 & 코드 분리
- 프로젝트가 커질수록 모든 API가 하나의 코드베이스에 있으면 관리가 어려워진다
- 멀티 모듈 구조에서는 각 API가 독립적인 코드베이스를 유지하면서도, 공통 모듈(common)을 재사용 가능하다
(예: common 모듈에서 DTO, Exception Handling 등을 관리)
✅ 4. CI/CD 파이프라인 개선
- 단일 모듈에서는 모든 API가 하나의 배포 파이프라인을 공유해야 한다
- 하지만 멀티 모듈 구조에서는 각 API를 개별적으로 배포 가능하므로, 특정 API만 업데이트하는 배포가 가능하다
멀티 모듈 세팅 방법
1️⃣ 가장 최상단 Root 폴더에 settings.gradle.kts 파일 생성 후 설정 세팅
rootProject.name = "hotel-reservation-platform"
// 멀티 모듈 추가
include("common")
include("customer-api")
include("host-api")
include("admin-api")
- 위와 같이 rootProject 명을 설정하고, 멀티티 모듈을 include("${멀티모듈명}")로 설정
2️⃣ 프로젝트의 가장 최상단 Root 폴더에 build.gradle.kts 파일 생성 후 설정 세팅
plugins {
kotlin("jvm") version "1.9.22" // Kotlin JVM 버전을 Java 21에 맞춤
id("org.springframework.boot") version "3.4.3"
id("io.spring.dependency-management") version "1.1.7"
}
allprojects {
repositories {
mavenCentral()
}
}
subprojects {
apply(plugin = "java")
apply(plugin = "org.springframework.boot")
apply(plugin = "io.spring.dependency-management")
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21)) // Java 21 설정
}
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
}
}
- 코틀린, Java 모두 활용 가능하도록 세팅
3️⃣ 프로젝트의 가장 최상단 Root 폴더 하위에 각API 모듈 별로 디렉터리 및 build.gradle.kts 파일 세팅
hotel-reservation-platform/
├── build.gradle.kts # 루트 Gradle 설정
├── settings.gradle.kts # 멀티 모듈 선언
├── common/ # 공통 모듈
│ ├── build.gradle.kts
│ ├── src/main/java/com/booking/common/
├── customer-api/ # 고객용 API
│ ├── build.gradle.kts
│ ├── src/main/java/com/booking/customer/
├── host-api/ # 숙박 업체 API
│ ├── build.gradle.kts
│ ├── src/main/java/com/booking/host/
├── admin-api/ # 관리자 API
│ ├── build.gradle.kts
│ ├── src/main/java/com/booking/admin/
- common 모듈의 build.gradle.kts
dependencies {
implementation("org.springframework.boot:spring-boot-starter")
}
- 나머지 customer-api, host-api, admin-api 모듈의 build.gradle.kts
dependencies {
implementation(project(":common")) // 공통 모듈 참조
}
4️⃣ gradle 리프레쉬 후 각 모듈 실행 테스트
- gradle 리프레쉬
./gradlew --refresh-dependencies
- 각 모듈별 Spring Boot Application 실행 코드 추가
(예시: src/main/java/com/booking/customer/CustomerApiApplication.java)
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CustomerApiApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerApiApplication.class, args);
}
}
- 실행 테스트 (각 API 모듈별로 테스트)
./gradlew :customer-api:bootRun
./gradlew :host-api:bootRun
./gradlew :admin-api:bootRun
Github Repository
- 멀티 모듈 초기 구성 적용된 브랜치 공유
https://github.com/f-lab-edu/hotel-reservation-platform/tree/initial-settings
GitHub - f-lab-edu/hotel-reservation-platform: 호텔 예약 API 플랫폼
호텔 예약 API 플랫폼. Contribute to f-lab-edu/hotel-reservation-platform development by creating an account on GitHub.
github.com
- 해당 브랜치에는 추가로 IDE 네이버 자바 코드 fomatter, check style 등이 포함되어있다
생각 정리
1. 숙박 예약 서비스에 대한 초기 프로젝트 구조를 설계하기 위해,
멀티 모듈과 단일 모듈의 개념을 다시 정리하면서 장단점을 비교하게 됐다
2. 여러 장단점이 있었으나 서비스 규모가 커진 게 아니라, 이제 막 서비스를 시작하려는 현시점에서
과연 멀티 모듈로 구성하는 게 단일 모듈보다 나은 선택일까 짧게나마 고민해 보는 시간이 필요하다 생각했다
3. 분명히 멀티 모듈을 선택함으로써 갖는 단점도 있었으나,
이제 막 서비스 구상을 시작하려는 단계에서도 API 별로 '사용 대상'을 명확히 구분한다면,
충분히 멀티 모듈을 선택할 만한 주된 장점들이 있었다
4. 초기 단계라 할지라도 사용 대상에 따라 인증 체계를 다르게 구성하기 쉽다는 장점이 있었고,
당장은 트래픽 부하가 심각하진 않더라도 앞으로 서비스 규모가 커질 때,
상대적으로 어떤 사용 대상의 API가 부하가 심해질까 예측하는 것은 충분히 가능하기에 의미가 있었다
또한 사용 대상에 따라 별개의 Cron 작업이 필요하는 것 또한 초기 단계부터 예상이 가능하다고 보았다
5. 추가적으로 사용 대상에 따라 업데이트가 빈번하게 일어나거나,
상대적으로 업데이트가 빈번하게 일어나지 않을 것 같다는 예상도 포함하여,
초기 단계 일지라도 배포 시, 멀티 모듈이 이점을 가질 수 있을 것이라 판단했다
6. 하지만 지금과 같이 '사용 대상'에 따라 API를 구분하여 설계한다는 명확한 기준이 있었기 때문에
멀티 모듈이 이점이 생긴 것이며, 무작정 특정 도메인별로 모듈을 쪼개는 것은 이점보다 단점이 매우 클 것 같다
7. 최종적으로 멀티 모듈 세팅을 실습한 과정을 단계별로 정리하여,
향후에도 멀티 모듈 초기 구성이 필요해질 때 빠르게 구성할 수 있을 것 같다고 생각된다
'개발 일기' 카테고리의 다른 글
[사이드 프로젝트] 기능 분석: 약관 도메인 (0) | 2025.03.27 |
---|---|
[고찰하기] 레이어 및 패키지 구조 설계 (0) | 2025.03.23 |
[이해하기] Lock 성능 테스트 (0) | 2025.03.18 |
[이해하기] JVM에서의 Lock (0) | 2025.03.14 |
[이해하기] JVM에서의 스레드에 대한 이해 (0) | 2025.03.11 |