본문 바로가기

programing

멀티 모듈에 대해

이번 포스팅은 멀티 모듈에 대해서 알아보는 포스팅이다.

목표는 필자의 프로젝트를 멀티 모듈로 구성하는 것으로 모놀리식 아키텍처에서 MSA 아키텍처로 나아가게 해서 모든 모듈을 각각 실행하게끔 만들 수 있을지 자신은 없지만 적어도 각 계층을 모듈화 하고 REST API와 애플리케이션 실행 부분은 분리해서 배포하게끔 하겠다.

 

멀티 모듈에 대해 알아보기 전 필자가 말한 모놀리식 아키텍처와 MSA를 알아보고 넘어가자.

둘은 소프트웨어 시스템을 구성하는 두가지 주요 아키텍처 패턴이다.

 

모놀리식 아키텍처(Monolithic Architecture)

특징 - 모든 기능이 하나의 코드베이스에 포함되고 애플리케이션은 하나의 단일 배포 단위로 구성된다. 보통 하나의 데이터 베이스를 공유하고 애플리케이션 전체를 한 번에 빌드하고 배포한다.

 

장점 - 초기 설계와 개발이 단순하다. 모든 기능이 하나의 프로젝트에 있기 때문에 코드 관리가 쉬우며 하나의 프로세스에서 실행되므로 내부 호출이 메모리 안에서 일어나기 때문에 성능이 좋다. 통합된 환경에서 모든 것이 동작하기 때문에 디버깅과 테스트가 비교적 쉽다.

 

단점 - 특정 기능만 확장하기 어렵다. 전체 애플리케이션을 함께 확장해야 하고 코드 베이스가 커질수록 유지보수가 어렵고 작은 변경도 전체 시스템에 영향이 끼치게 된다. 작은 변경에도 애플리케이션을 빌드하고 배포해야 한다.

 

마이크로 서비스 아키텍처 MSA(Microservices Architecture)

특징 - 애플리케이션을 독집적으로 배포하고 확장, 관리할 수 있는 작은 서비스 단위로 나누고 각 서비스는 도유한 기능을 담당하며 각 서비스는 독립된 데이터베이스를 가질 수 있다. 그리고 각 서비스는 독립적인 배포가 가능하다.

 

장점 - 특정 서비스만 독립적으로 확장할 수 있으며 자주 사용되는 서비스만 확장하여 리소스를 효율적으로 사용할 수 있다. 각 서비스는 독립적이기 때문에 작은 변경에도 전체 시스템에 영향을 미치지 않고 배포 속도도 빠르고 위험이 감소한다. 새로운 기술을 도입이 편하다.

 

단점 - 서비스 간 통신, 데이터 일관성, 배포 파이프라인 등 시스템의 복잡성이 증가한다. 많은 서비스가 독립적으로 운영되기 때문에 모니링, 로깅, 장애 처리 등 운영 관리가 어려워질 수 있다. 서비스 간 통신이 네트워크를 통해 이루어지므로 성능에 영향이 미칠 수 있고 각 서비스에 독립적인 데이터 베이스를 가질 때 데이터 일관성을 유지하는 것이 어려울 수 있다.

 

필자는 저번 카프카 예제에서 멀티 모듈을 처음 다뤄 보았고 이전부터 관심은 있어서 조금씩 해보던 도중 생각보다 구성이 어려워서 다른 공부부터 하고 이제야 시작한다.

 

멀티 모듈 아키텍처

큰 프로젝트를 여러 개의 모듈로 나누어 관리하는 방식이다. 각 모듈은 독립적으로 개발, 테스트, 배포될 수 있고 특정 기능이나 도메인을 캡슐화 한다. 멀티 모듈 아키텍처를 올바르게 구성하면 코드 재사용성, 유지보수성, 테스트 용이성이 향상된다. 

MSA와 비슷한 장단점과 특징을 가지고 있다.

비슷한 장단점과 특징을 가지고 있지만 MSA는 API 게이트웨이를 통한 기능별 API 서버 분할, 멀티 모듈은 하나의 애플리케이션에서 여러 개의 영역으로 구분되고 이것이 하나의 프로젝트에서 관리되는 것이다.

 

좋은 아키텍처에 대한 부분이 있는데 이는 시스템이 모놀리식 구조로 단일 파일로 배포 되더라도 이후엔 독립적으로 배포 가능한 단위들의 집합으로 성장하고 독립적인 서비스나 마이크로서비스 수준까지 성장할 수 있도록 만들어져야 한다는 것이다. 또한 나중에 상황이 바뀌어서 진행 방향을 거꾸로 돌려 원래 형태인 모놀리식 구조로 되돌릴 수도 있어야 한다는 것이 좋은 아키텍처, 즉 클린 아키텍처이다.

 

본 포스팅은 인프콘이나 우아한 멀티 모듈 세미나를 정리하고 필자가 완벽히 이해하고 사용하며, 설명할 수 있을지 모르겠지만 나름의 정리와 결과를 도출해 내도록 하겠다.

 

아키텍처는 프로젝트 초기에 이루어져야 하는 일련의 설계 결정이다.

아키텍처는 요소의 구조와 그 관계에 대한 것이다.

 

멀티 모듈의 잘못된 설계

 

core와 common의 모듈을 admin, api, batch등 각 서버가 의존하게 될 때 작은 프로젝트에서는 문제가 없겠지만 점점 서비스 규모가 늘어갈수록 하위의 서비스는 점점 커져가고 공통적인 기능들이 많아질 것으로 중복을 제거하기 위해 core와 common의 규모는 커질 것이다.

 

1. 서비스 복잡도에 따라 데이터 스토어가 늘어나게 되고 중복을 제거하기 위해 core와 common은 커질 수밖에 없다.

트래픽이 늘어갈수록 커넥션 할당에 Too many connections가 생길 수 있다.

 

2.특정 모듈이 하위 버전 라이브러리를 참조하는 경우 업그레이드가 난해하다.

 

3.Copy and Paste 문제로 예시로 API 스펙에 맞춘 서비스를 ADMIN 서비스에서 사용하게 될 때 API 스펙에 맞춘 서비스를 가져와 분기를 사용해 참조 후 수정하게 되는 것으로 참조하는 클래스가 많다면 어디서 사이드 이펙트가 생길지 모른다. 이때 깨진 창문 효과로 파급이 커질 수 있다.

 

4. 전체 빌드 배포문제로 글자 하나 오타일 때 배포를 위해 전체를 빌드하고 배포해야한다. 이렇다면 모든 시스템에 영향이 미치게 되고 비용도 상승한다.

 

이로 인해 멀티 모듈 프로젝트를 어떤 기준으로 나뉘어야 할지 확인해 보자.

 

먼저 역할, 책임, 협력 관계가 올바른지 확인해야 한다.

 

이렇게 서비스가 확장된다면 기술 베이스 지향적인 모듈 구조라고 볼 수 있다.

 

이때 도메인의 위치를 고민해야 한다.

 

필요한 도메인들을 메타 모듈에 집합되어 있을 때 track은 mysql, lyric은 MongoDB에 적재될 때 메타 도메인은 어디에 위치해야 하는가?이다.

 

메타 모듈의 도메인이 의존하는 유관부서나 업체연동 모듈 등이 지속적으로 늘어나게 되고 버전업이 될 때 복잡하고 점점 커지게 된다.

 

이때 늘어나는 멀티 모듈들을 어떤 기준으로 분리하고 구성해야 할까?

Core와 Common을 삭제하고 Core와 Common이 정말로 필요한가? 를 생각해야 한다.

중복 제거가 중요하지만 중복을 하나의 모듈에 집중하게 된다면 그것도 문제가 된다.

 

DDD Bounded Context - 도메인 모델이 적용되는 경계를 정의한다. 각각의 바운디드 콘텍스트는 독립된 모델을 가지며, 다른 바운디드 콘텍스트와는 명확한 경계를 가진다. Bounded Context는 DDD의 핵심 개념으로 DDD는 Domain-Driven Design의 약자로, 소프트웨어 개발의 철학 및 접근 방식을 의미한다. 주요 목표는 소프트웨어 모델이 실제 비즈니스 도메인을 정확하게 반영하도록 하는 것이다.

 

이를 통해 기준이 되는 멀티 그룹을 구성해야 한다.

 

서버 모듈은 잦은 변화가 생기는 그룹을 모듈로 구성

데이터 모듈은 서버 모듈과 밀접한 관계를 가지고 데이터 스토어를 핸들링하게 된다.

연동 모듈은 유관부서나 업체 연결에 관한 그룹으로 버전업이 될 때 큰 변화가 생긴다.

클라우드(system) 모듈은 컨테이너 환경과 트래픽 제어를 위한 시스템 관련 모듈로 변화가 적은 그룹이다.

각자 보유한 성격과 특성, 사이클이 공통된 부분을 분리해 그룹을 형성해야 한다.

 

어떻게 멀티 모듈 그룹을 분리하고 사용해야 하는가?

 

 

그룹으로 분리한 멀티 모듈을 하위로 구성하고 멀티 그룹 성격에 맞게 프로젝트를 구성한다.

가독성이 증가되고 그룹 폴더 명을 기준으로 의존성을 추가할 수 있다.

 

위와 같은 프로젝트 구성을 가져갈 수 있다. 하지만 문제점이 생기기도 한다. 모듈이 늘어나고 빌드시간이 늘어나고 이벤트 발생 시 웹훅이 일어날 때 다른 코드에도 반응하게 될 수 있다.

이 문제를 해결하기 위해서 멀티 그룹에 특성에 맞게 다시 나누어 본다.

 

이 것은 프로젝트를 분리함으로 빌드 시간도 줄어들고 프로젝트 경계도 명확하고 인터페이스 구현 설계도 명확해진다.

그렇다면 분리된 각 저장소 별로 상호구현에 대해 알아보자.

 

예시로 Playback 도메인은 AOD를 통해 실행될 때 아티팩토리에 저장소에 빌드 타임에 라이브러리를 업로드하게 되고 데이터에서는 의존성을 선언해서 사용하게 된다.

 

 

인프라에 저장소가 있고 배치를 통해 에이전트 수가 많을 때 too many connections를 만나게 된다.

 too many connections을 피하기 위해 데이터 접근을 데이터 모듈로 이동하고 호출과 응답을 분리한다.

인프라는 aod 서버를 올바르게 호출하기 위해 구현되어야 한다.

협력 관계에서 주고받는 메시지가 객체의 책임을 결정하고 책임을 자율적으로 만들어야 한다.

 

 

부트와 데이터의 관계에서 서비스 구현체를 어디에 두어야 하냐가 큰 관심사가 된다.

자바 스프링 프레임워크에서 흐름은 요청과 응답에 따라 컨트롤러 - 서비스 - 리포지토리를 순회하며 기능을 수행하게 될 때, 이때 서비스는 어디에 위치해야 하는지는 둘 다 서비스가 필요하다 이다.

 

 

서비스 구현은 모듈별로 책임과 역할에 맞게 각각 구현되어야 하고 서로 협력해야 한다. 요청 값에 따른 boot의 서비스 이벤트 발생이 data 모듈의 서비스가 저장하는 방식으로 저장해야 한다.

data 메타 모듈은 웹 서버에 의존적인 객체를 전달해서는 안 된다. 데이터 메타 모듈은 배치나 여러 모듈에서 사용될 수 있기 때문에 웹 서버에 강한 의존성이 생기면 테스트할 때 등 mock 라이브러리를 의존하게 되고 이로써 데이터 메타 모듈의 의미를 상실하게 되기 때문이다.

 

정리 

왜 멀티 모듈 구조가 중요할까?

- 잘못 구성되면 변경하기 어렵다.

- 프로젝트 초기에 이루어져야 하는 일련의 설계 과정이다.

- 개발 생산성에 막대한 영향을 미친다.

 

무엇을 기준으로 멀티 모듈 프로젝트 구조를 나눠야 할까?

- 경계 안에서 의미를 가질 수 있는 그룹을 정의하는(나누는) 것이 중요하다.

- 역할, 책임, 협력 관계가 올바른지 다시 한번 생각한다.

 

어떻게 실전 멀티 모듈 프로젝트 구현을 해야 할까?

- 프로젝트가 커지고 있다면 다시 경계를 나누고 그 기준으로 소스 저장소를 분리한다.

- 인프라(외부) 라이브러리에는 DATA 관련 구현을 지양해야 한다. 인프라는 외부 서비스 연동을 위한 모듈인데 내부적인 서비스 연동 모듈이 들어가면 오염이 될 수 있으니 서버를 위해 독립적으로 구현할 수 있도록 해야 한다.

- 서비스 구현은 각자 역할에 맞게 각각 구현될 수 있다. 공통으로 한쪽에 구현하지 않는다.

- 시스템 레벨 구현이 실제 서비스 애플리케이션과 밀접하게 연관되지 않도록 격리하거나 분리해야 한다.

 

멀티 모듈 설계 구조를 가져가는 것은 유연해야 하고 기준을 잡는 것이 가장 중요한 것 같다.

https://www.youtube.com/watch?v=ipDzLJK-7Kc&t=270s

 

해당 포스팅은 위 동영상을 정리한 내용으로 멀티 모듈 관련 처음 작성하는 글이기에 이렇게 구성해야 한다.라는 것보다 멀티 모듈에 대해서 어떤 기준을 가지는 게 좋고 어떤 사이드 이펙트를 생각을 해야 하는가? 에 관한 정리를 할 수 있었던 시간이었고 본 포스팅과 같이 다른 분의 포스팅이나 영상을 가지고 두 세편 정도 멀티 모듈에 대해서 공부를 더 해보고 나는 어떤 식으로 구성을 해야 좋을지 틀을 잡아 보려고 하기 때문에 포스팅 몇 편은 멀티 모듈에 대해서 공부하는 포스팅이 될 것 같다. 만약 보시는 분들이 계시다면 몇 편의 내용은 중복되는 내용이 있을지더라도 저의 개인적인 견해를 끝에 달아서 정리해 보도록 하겠습니다.

'programing' 카테고리의 다른 글

알고리즘 LIST  (0) 2024.06.24
kafka connect에 대해  (0) 2024.06.21
멀티 모듈-3  (1) 2024.06.10
멀티 모듈 - 2  (2) 2024.06.09
kafka KRaft  (1) 2024.06.08