본문 바로가기
개인 공부 일지/아키텍처

소프트웨어 아키텍처 및 시스템 설계 - (5) 소프트웨어 아키텍처 패턴

by 대체로 무해함 2025. 9. 14.

해당 시리즈는 【한글자막】 소프트웨어 아키텍처 및 대규모 시스템 설계 강의를 보고 정리한 내용입니다.

소프트웨어 아키텍처 패턴 - 멀티 티어 아키텍처

  • 시스템 계층을 논리적, 물리적으로 나눈 것
    • 논리적 분리는 각 계층의 책임의 범위를 결정함
    • 물리적 분리는 각 팀마다 시스템을 배포 또는 업그레이드, 확장하는 영역
  • 멀티 레이어 아키텍처와 다른 개념으로 하나의 어플리케이션에 대한 멀티 레이어 아키텍처와 달리 각 계층마다 별도의 기기에 실행됨
  • 물리적 계층을 분리하면서 배포와 업그레이드가 분리되어 진행되는 이점이 있으나 설계가 단순해지는 제약 사항이 존재함
    • 인접한 계층과 짝을 이루는 어플리케이션들은 클라이언트 - 서버 형식으로 동작함
    • 계층을 뛰어넘어서 통신을 할 순 없음
    • 제약 사항을 통해 각 계층 간 결합이 느슨해짐

변형 패턴 - 3 Tier Architecture

  • 클라이언트 - 서버 구조의 웹 기반 서비스에 주로 사용되는 보편된 아키텍처 패턴
  • 서비스를 다음의 3가지 계층으로 구분함
    • Presentation Tier
      • 상위 계층으로 사용자 인터페이스가 포함됨
      • 사용자에게 정보를 나타내고, 그래픽을 통해 입력값을 받는 것을 목표로 함
      • 대표적으로 웹 페이지, 모바일 App이나 데스크탑 어플리케이션이 있음
      • 비즈니스 로직을 포함하지 않으며 이는 브라우저에서 실행되는 코드가 사용자에게 직접적으로 나타나기 때문임
    • Appliocation Tier
      • Business Tier 혹은 Logic Tier로 불림
      • 모든 기능을 담당하는 계층으로 기능 요구 사항을 갖춘 계층
      • 받은 데이터를 처리하고, 관련 있는 비즈니스 로직에 적용하는 역할
    • Data Tier
      • 사용자 데이터나 비즈니스 데이터를 저장하고 유지하는 역할
      • 파일 시스템의 파일이나 데이터베이스가 포함됨

많이 사용되는 이유

  • 다양한 종류의 사용 사례에 적합함 - 대표적으로 웹 사이트, 웹 서비스
  • 수평적인 확장이 쉬움
    • 로드 밸런서를 두고 Application Tier의 인스턴스를 확장
    • 데이터베이스를 복제하거나 분산하여 확장
  • Application Tier에 모든 로직이 집중되므로 별도의 통합 작업이 불필요함
  • 한계점 : 비즈니스 로직 계층이 단일 계층 구조로 단일 런타임 단위의 단일 코드로 집약됨
    • 과도하게 집약된 메모리를 소모함 ⇒ 속도가 느려짐(가비지 콜렉션 등)
    • 코드가 크고 복잡해짐에 따라 개발 속도가 느려짐
      • 논리적으로 어플리케이션을 개별 모듈로 나눠 해결할 수 있으나 이는 모듈별로 강하게 결합하게 됨
      • 어플리케이션 전체가 배포되어야 각 세부 기능들이 배포될 수 있음
  • 코드 베이스 규모가 비교적 작고 복잡하지 않은 기업에 적합한 선택지

변형 패턴

2계층 아키텍처

  • Presentation + Business Tier와 Data Tier로 분리하는 방법
  • 중간 단계인 Logic Tier가 제거되므로 오버헤드가 줄고, 보다 빠른 네이티브 앱 경험을 제공할 수 있음
  • 데스크탑, 모바일의 에디터가 대표적으로 해당됨

4계층 아키텍처

  • 3계층에서 Presentation Tier와 Application Tier 사이에 하나의 계층을 추가하는 방법
  • 예를 들어 API Gateway 계층을 만들어 보안, 캐싱, API, 포맷 변경 등의 기능을 수행할 수 있음

4+n계층 아키텍처

  • 보기 힘든 패턴
  • 계층이 늘수록 성능이 이점이 무조건적으로 늘지 않고, 계층 구분에 따른 오버헤드가 발생함
    • 제약 사항을 지키지 못하면 각 계층이 강하게 결합되는 문제도 존재함
    • 이런 경우 더 작게 쪼개는 아키텍처를 사용함

소프트웨어 아키텍처 패턴 - 마이크로서비스 아키텍처

마이크로서비스 아키텍처

  • 비즈니스 로직이 연결되어 있고, 독립적으로 배포된 서비스로 조직함

  • 3계층 아키텍처는 Logic Tier에 모든 비즈니스 로직이 집중되어 Monolithic 아키텍처라고도 함

    • 코드 베이스가 커지고 복잡해지면 문제 해결이 어려워지고, 새로운 기능 추가가 힘듦

    • 조직적 확장성에 문제가 생기게 됨

      ⇒ 마이크로서비스 아키텍처로의 확장

  • 작은 서비스를 각 팀에서 담당하므로 책임 범위가 좁음

  • 장점

    • 더 작은 코드베이스
      • 개발 자체가 쉽고 빠름
      • 코드 빌드와 테스트가 빠름
      • 문제 해결 및 기능 추가가 쉬움
    • 인스턴스를 분리하면서 CPU 부담과 메모리 소모가 덜하기 때문에 하드웨어 요구치가 낮아짐
      • 성능 낮은 하드웨어를 통한 확장도 가능함
    • 조직적 확장성이 뛰어남
      • 개별적으로 개발, 유지, 배포가 이뤄지므로 처리량이 높아짐
      • 각 팀은 자율적으로 원하는 언어, 기술, 스케줄을 결정할 수 있음
    • 결함 격리 형태로 더 높은 보안성 제공
      • 서비스 문제 발생 시 모놀리식에 비해 더 쉽게 분리하여 해결 가능함
  • 한계점

    • 마이크로서비스 아키텍처에 따른 이점은 쉽게 얻기 힘듦
      • 단순히 코드를 분할하는 것 이외에도 추가적인 지식이 필요함
        • 제대로 알지 못할 경우 Big Ball of Mud가 됨
    • 상당한 오버헤드량에 따른 문제 해결이 필요함
    • 개별 개발, 배포를 위한 완전한 조직 분리를 요구함 (모든 서비스를 논리적으로 분리)
  • 마이크로서비스 아키텍처의 이점을 얻기 위해 다음의 규칙들을 참고해야 함

    1. Single Responsibility Principle (단일 책임 원칙, SRP)
      • 각 서비스가 하나의 서비스, 도메인, 리소스, 액션을 책임져야 함
    2. Seperate Database Per Service (서비스 단위 데이터베이스 분리)
      • 서비스가 데이터베이스를 공유할 경우 데이터베이스 변경에 모든 서비스(팀)가 협력이 이뤄져야 함
      • 데이터베이스를 분리하여 업데이트나 변경 사항을 쉽게 파악하는 이점을 가질 수 있음
      • 이는 각 서비스를 완전히 독립된 환경으로 분할함 (데이터 중복 오버헤드는 감수해야 함)

소프트웨어 아키텍처 패턴 - 이벤트 기반 아키텍처

이벤트 기반 아키텍처?

  • 마이크로서비스끼리 통신할 경우 서로의 존재를 알아야 하고, 요청에 대해 응답을 기다려야 함
    • 이는 각 서비스에 대한 의존성이 발생함
  • 이벤트 기반 아키텍처는 다이렉트 메시지나 데이터를 요구하는 대신 이벤트로만 진행함
    • 이벤트는 사실이나 변경을 증명하는 역할을 함
  • 이벤트 기반 아키텍처는 다음과 같은 구성 요소를 가짐
    1. Event Emitter / Producer
    2. Consumer
    3. Message Broker
  • 장점
    • 의존성이 제거됨
      • 이벤트를 생산해 통신하므로 서비스는 서로의 존재를 몰라도 됨
      • 모든 메시지는 전적으로 비동기로 교환됨
    • 높은 확장성
      • 새로운 기능(서비스)는 기존 채널을 구독함으로써 기존 데이터를 얻을 수 있음
      • 구독 과정에서 어떠한 시스템의 변경도 요구하지 않음
    • 데이터 스트림이나 패턴 감지를 실시간으로 수행할 수 있음

Event Sourcing 패턴

  • 현재 상태를 데이터베이스에 저장하는 대신 다시 돌려볼 수 있는 이벤트를 저장할 수 있음
  • 중간에 트랜잭션에 문제가 발생할 경우 해당 트랜잭션을 보상하는 트랜잭션을 추가하여 해결할 수 있음
    • 이는 사용자를 동결 시키거나 데이터베이스 레코드를 수정하지 않아도 됨

CQRS 패턴

  • C = Command, Q = Query, R = Responsibility, S = Segregation
  • 해결하는 문제
    • 읽기와 업데이트 작업이 많은 데이터베이스 최적화 문제
      • 병행 연산을 적용하는 경우 전체적인 작업 속도가 하락함
      • 동작이 집중된 작업을 최적화할 경우 다른 작업을 희생해야 함
      • CQRS 패턴은 각 작업을 각각의 데이터베이스로 나눠 별도의 서비스에 둠
        • 업데이트가 발생할 때마다 이벤트를 발생시키고, 읽기 DB는 이를 읽어 업데이트함
        • 이벤트로 연결되면서 각 작업은 서로의 간섭 없이 진행할 수 있음
    • 다중 테이블 연결 문제
      • 데이터베이스를 분리하면서 다중 테이블 대상으로 레코드 연산이 힘들어짐
      • 서비스별로 보낼 경우 속도가 느리고, 서비스별로 사용하는 데이터베이스가 다를 수 있음
      • CQRS 패턴은 각 데이터베이스가 변경될 때마다 채널로 이벤트를 생성함
        • 다중 테이블 연산하는 서비스는 이를 구독하고, 변경이 발생하면 별도의 읽기 전용 데이터베이스(View)에 저장함
        • 사용자 요청 시 JOIN이 이뤄진 View를 통해 결과를 전송함