[MSA] Mongs Backend 아키텍처 설계 1편 | Layered Architecture (레이어드 아키텍처)

2025. 8. 14. 09:27·개발/architecture

시작은 익숙한 레이어드 아키텍처로

프로젝트의 시작은 가장 익숙한 레이어드 아키텍처였다.
서비스 초기에 중요한 건 복잡한 설계보다 빠르게 동작하는 결과물을 내는 것이었고, 레이어드 구조는 단순하면서도 직관적이어서 빠른 개발에 적합하다고 생각했다.


서비스 구조 설계

애플리케이션의 구조

서비스 구조는 전통적인 레이어드 아키텍처를 기반으로 Controller, Service, Repository 세 계층으로 나누고 외부 이벤트 처리를 위해 Mqtt Consumer를 추가했다.

 

Controller 영역

  • 클라이언트의 요청을 가장 먼저 받는 진입점 역할이다.
  • 요청을 검증하고, 비즈니스 로직 실행을 위해 Service 계층을 호출한다.
  • REST API 및 Mqtt 요청의 엔드포인트 역할을 담당한다.

Consumer 영역

  • 외부 메시지 브로커에서 발행된 이벤트를 구독하고 처리하는 역할을 한다.
  • 수신한 메시지를 가공하여 Service 계층으로 전달함으로써, 실시간 이벤트 기반의 처리를 가능하게 한다.
  • 배틀 플레이어의 공격/수비/방어 선택 이벤트를 처리하는 역할을 한다.

Service 영역

  • 핵심 비즈니스 로직을 담당하는 계층이다.
  • Controller 와 Consumer 에서 전달 받은 요청을 처리하고, 필요 시 외부시스템과 상호작용한다.

Repository 영역

  • 데이터 접근 계층 (DAO)
  • Service 계층에서 호출되어 Database, Redis 등 영속화 계층과 직접 통신한다.
  • 애플리케이션 코드에서 데이터 소스 접근 로직을 캡슐화하여 분리한다.

MSA 구조 설계

전체적인 구조

서비스의 핵심 로직을 담당하는 여러 마이크로 서비스로 구성된 Application 영역과 공통적으로 참조되는 외부 시스템 (DB, Redis, Mqtt)인 External Systems 영역으로 구분했다.

 

Application 영역

  • 공통 인프라 서비스
    1. Eureka
      • 서비스 디스커버리를 담당한다.
      • 마이크로서비스들이 동적으로 등록되고, Gateway 및 다른 서비스에서 이를 검색하여 사용할 수 있게 했다.
    2. Gateway
      • 클라이언트 요청의 진입점으로 모든 요청 처리를 담당한다.
      • 라우팅을 통해 적합한 마이크로 서비스로 요청을 전달하는 역할을 한다. 
      • 도메인 Auth 서비스를 통해 인증을 진행한다.
      • 모든 서비스에서 공통적으로 사용하는 정보와 인가 정보를 담은 Passport를 발급 받아 마이크로 서비스로 함께 전달한다.
      • EntryPoint로 접근하는 모든 요청을 로깅한다.
  • 도메인 서비스
    1. Auth
      • 사용자에 대한 인증 정보를 관리한다.
      • 사용자에 대한 인가 정보를 담은 Passport를 발행한다.
      • JWT 기반 토큰을 통해 인증 정보를 관리한다.
    2. Battle
      • 배틀 도메인을 담당하는 서비스 그룹으로 사용자 간 배틀 요청을 처리한다.
      • 사용자 간 배틀 흐름을 제어하고, 배틀 결과 처리를 담당한다.
    3. Management
      • 캐릭터의 상태 관리 요청을 처리한다.
      • 캐릭터 생명 주기를 관리하는 스케줄러를 구동한다.
    4. Player
      • 플레이어 정보 관리 요청을 처리한다.
      • 플레이어 기본정보, 게임 진척도, 인벤토리 등을 관리한다.

External Systems 영역

  1. Database
    • 각 마이크로서비스의 영속화 계층을 담당한다.
    • 서비스 별로 독립 스키마를 가지게 했으며, 마이크로서비스 간 데이터베이스 공유를 최소화 하도록 했다.
  2. Redis
    • 캐시 및 인증 정보를 가진 세션을 관리하는데 활용했다.
    • Redis의 TTL을 통해 일정 시간 동안 할 수 없는 기능을 처리하기 위해 사용했다.
  3. Mosquitto (MQTT)
    • 메시징 시스템으로, 클라이언트와 서버 간 실시간 이벤트를 전달하여 데이터 동기화를 위해 사용했다.
    • 캐릭터 상태 변경 및 배틀 라운드 결과 이벤트, 플레이어 정보 변경 이벤트를 처리했다.

개발 진행중 문제점 발견

하지만 기능이 늘어나면서 몇 가지 문제점을 찾을 수 있었다.

 

  1. 중복 코드 발생
    • Battle, Management 모두 캐릭터 도메인에 의존하면서, DB 영속화 로직이 각 Application에 반복 구현됨
    • 건강 수치 증·감소와 변경 사항을 클라이언트에 비동기 메시지로 전달하는 로직도 두 모듈에 중복 존재
  2. 단일 책임 원칙(SRP) 위반
    • 캐릭터 관련 핵심 로직이 여러 Application(Service)에 분산되어 있어, 변경 시 여러 모듈을 동시에 수정해야 함
    • 하나의 유스케이스 흐름이 나뉘어 있어 책임 경계가 불명확함
  3. 응집도 저하
    • 캐릭터 도메인 로직이 한 곳에 모이지 않고 분산되어 있어, 로직 위치 파악이 어렵고 기능 확장 시 영향 범위 파악이 어려움
  4. 재사용성 저하
    • 동일한 도메인 동작이 각 모듈에 별도로 구현되어, 다른 Application에서 활용이 어렵고 재사용 불가
  5. 테스트 비용 증가
    • 로직이 분산·중복되어 단위 테스트 케이스도 중복 작성 필요
    • 변경 시 테스트 범위도 넓어져 유지보수 비용이 커짐
  6. 변경 전파 비용 증가
    • 로직 수정 시 Battle과 Management 모두 수정해야 하며, 변경 누락 시 버그 발생 가능성 상승

개선 방향 고민

  1. 도메인 모듈화 및 응집도 향상
    • 도메인과 연관된 비즈니스 로직은 도메인별 개별 모듈로 분리하여 관리
    • 캐릭터 도메인 로직(건강 수치 변경, 상태 검증 등)은 CharacterDomainService와 같이 한 곳에서만 구현 → 중복 제거 및 응집도 향상
    • 비즈니스 로직은 해당 도메인 모듈을 호출하도록 변경 → 책임 경계 명확화
  2. 외부 연계 모듈화
    • 외부 시스템 연계 로직(MQTT, Redis, DB 등)은 각 외부 시스템별 개별 모듈로 분리
    • 비즈니스 로직은 외부 연계 모듈의 인터페이스를 통해 호출 → 테스트 시 Mock 교체 용이
    • 예) MqttNotificationService, RedisCacheService 등으로 구성 → 재사용성 강화 및 시스템 의존성 최소화
  3. 아키텍처 계층 책임 분리
    • Business Service는 유스케이스 흐름 제어만 담당
    • Domain Service는 순수 도메인 규칙만 담당
    • Client Service는 외부 시스템 연계만 담당
    • 이를 통해 계층 침범 방지 및 유지보수성 향상
  4. 테스트 용이성 확보
    • 도메인 로직이 인프라 의존 없이 독립 실행 가능해져, 순수 단위 테스트 가능
    • 외부 연계 모듈은 Mock/Stubbing으로 대체 가능 → 테스트 속도 및 안정성 향상
  5. 확장성과 변경 용이성 확보
    • 새로운 Application(Battle 외 다른 게임 모드 등)에서 동일 도메인 로직 재사용 가능
    • 외부 시스템 교체(MQTT → Kafka) 시에도 도메인 및 Application Service 코드 수정 최소화

앞으로는?

처음에는 누구나 빠르게 파악할 수 있는 단순한 구조가 가장 좋다고 생각했다.

하지만 서비스가 커질수록 단순한 구조가 오히려 발목을 잡았다.

 

이번 과정을 통해 배운 건,

빠르게 만들지만, 언제든 구조를 개선할 수 있도록 준비해야 한다는 것이다.

 

앞으로는 기능을 추가할 때마다

"이 로직은 어떤 레이어에 배치하는 것이 적합할까?

스스로 질문하면서 구조에 대한 고민을 깊게하여 다듬어 가야겠다고 느꼈다.

'개발 > architecture' 카테고리의 다른 글

[MVVM] Mongs Android 아키텍처 설계 1편 | Model-View-ViewModel  (0) 2025.08.14
'개발/architecture' 카테고리의 다른 글
  • [MVVM] Mongs Android 아키텍처 설계 1편 | Model-View-ViewModel
tableMinPark
tableMinPark
Backend Engineer
  • tableMinPark
    Sangmin's Tech Blog
    tableMinPark
  • 전체
    오늘
    어제
  • 블로그 메뉴

    • tech study blog
    • my github
    • monglife github
    • 분류 전체보기 (48)
      • 개발 (7)
        • java (0)
        • kotlin (0)
        • spring boot (0)
        • android (0)
        • junit5 (5)
        • architecture (2)
      • 데브옵스 (3)
        • docker (3)
        • github action (0)
        • grafana (0)
        • prometheus (0)
        • elk (0)
      • 알고리즘 (35)
        • baek joon (0)
        • programmers (4)
        • leet code (29)
      • 일상 (3)
        • Wear OS 앱 개발기 (2)
        • 회고 (1)
  • 태그

    Android
    MVVM
    Kotlin
    ubuntu
    monglife
    bind mount
    volume
    docker network
    MSA
    레이어드 아키텍처
    mongs
    Container
    docker-compose
    micro service
    java
    docker compose
    Thread
    jetpack-compose
    wear os
    synchronized
    20.04
    docker
    Galaxy watch
    apple watch
    layered architecture
  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
tableMinPark
[MSA] Mongs Backend 아키텍처 설계 1편 | Layered Architecture (레이어드 아키텍처)
상단으로

티스토리툴바