01-02.모놀리식 지옥과 분해 전략

Part 1. 모놀리식 지옥에서 벗어나라

모놀리식 아키텍처의 장점

  • 개발이 간단하다: IDE 등 개발 툴은 단일 애플리케이션 구축에 초점이 맞추어져 있다.

  • 애플리케이션을 쉽게 변경할 수 있다: 코드, DB 스키마를 변경해서 빌드/배포하기 용이하다.

  • 테스트하기 쉽다: 개발자가 애플리케이션을 띄우고, REST API를 호출하고, 셀레늄으로 UI를 시험하는 종단 간 테스트를 작성합니다.

  • 배포하기 쉽다: 개발자는 서버에 접속하여 톰캣 설치 경로에 WAR 파일을 복사하면 그만입니다.

  • 확장하기 쉽다: 부하 분산기 뒷면에 애플리케이션 인스턴스를 여러 개 실행합니다.

모놀리식 아키텍처의 단점

  • 너무 복잡해서 개발자가 주눅 들다.

  • 개발이 더디다.

  • 커밋부터 배포에 이르는 길고 험난한 여정.

  • 확장하기 어렵다.

  • 확실하게 전달하기 어렵다.

  • 갈수록 한물간 기술 스택에 발목이 붙잡히다.

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

  • 크고 복잡한 애플리케이션을 지속적으로 전달/배포할 수 있다.

    • 자동하 테스트

    • 독립적인 배포

    • 여러 기술 조직의 꾸림

  • 서비스 규모가 작아 관리하기 쉽다.

  • 서비스를 독립적으로 배포/확장할 수 있다.

  • 마이크로서비스 아키텍처 덕분에 팀이 자율적으로 움직인다.

  • 결함 격리가 잘 된다.

  • 새로운 기술을 실험하고 도입하기 쉽다.

마이크로서비스 아키텍처의 단점

  • 딱 맞는 서비스를 찾기 쉽지 않다.

  • 분산 시스템은 너무 복잡해서 개발, 테스트, 배포가 어렵다.

  • 여러 서비스에 걸친 기능을 배포할 때에는 잘 조정해야 한다.

  • 마이크로서비스 아키텍처 도입 시점을 결정하기 어렵다.

마치며

  • 모놀리식 아텍처 패턴은 애플리케이션을 하나의 배포 단위로 구성합니다.

  • 마이크로서비스 아키텍처 패턴은 독립적으로 배포 가능하면서 자체 DB를 보유한 서비스들로 시스템을 분해합니다.

  • 단순한 애플리케이션은 모놀리식 아키텍처가, 크고 복잡한 애플리케이션은 마이크로서비스 아키텍처가 더 적합한 선택입니다.

  • 마이크로서비스 아키텍처를 채택하면 자율적인 소규모 팀들이 작업을 병행할 수 있어서 소프트웨어 개발 속도가 빠릅니다.

  • 마이크로서비스 아키텍처는 만병통치약이 아닙니다. 복잡성을 비록하여 중요한 단점도 있습니다.

  • 마이크로서비스 아키텍처 패턴 언어는 마이크로서비스 아키텍처로 애플리케이션을 설계할 때 유용한 패턴들의 모음집입니다. 패턴 언어는 마이크로서비스 아키텍처 도입 여부 결정 시 유용하며, 마이크로서비스 아키텍처를 효과적으로 적용하는 충실한 안내자입니다.

  • 소프트웨어 전달 속도를 높이려면 마이크로서비스 아키텍처만으로는 부족합니다. 소프트웨어를 성공적으로 개발하려면 데브옵스 및 자율적인 소규모 팀들이 있어야 합니다.

  • 마이크로서비스를 검토할 때 인간적인 측면도 고려해야 합니다. 직원들이 느끼는 감정도 충분히 반영되어야 성공적인 전환이 가능합니다.

Part 2. 분해 전략

마이크로서비스 아키텍처란 무엇인가?

마이크로서비스 아키텍처의 핵심 사상은 기능 분해

  • 대규모 단일 애플리케이션을 개발하는 대신 애플리케이션을 여러 서비스로 구정하자는 의미

소프트웨어 아키텍처의 정의와 중요성

소프트웨어 아키텍처의 정의

컴퓨팅 시스템의 소프트웨어 아키텍처는 소프트웨어 엘리먼트와 그들 간의 관계, 그리고 이 둘의 속성으로 구성된 시스템을 추론하는 데 필요한 구조의 집합이다.

  • 핵심은 애플리케이션 아키텍처가 여러 파트(엘리먼트)로의 분해와 이런 파트 간의 관계(연관성)이라는 것

분해가 중요한 이유

  • 업무와 지식의 분리로 전문 지식을 보유한 사람들이 함께 생산적으로 애플리케이션 작업을 할 수 있다.

  • 소프트웨어 엘리먼트가 어떻게 상호 작용하는지 밝힌다.

.

소프트웨어 아키텍처의 4+1 뷰 모델

  • 논리 뷰: 개발자가 작성한 소프트웨어 엘리먼트. 객체지향 언어라면 클래스, 패키지가 해당되며 결국 상속, 연관, 의존 등 클래스와 패키지의 관계를 말합니다.

  • 구현 뷰: 빌드 시스템의 결과물, 모듈과 컴포넌트로 구성됩니다. 자바에서 모듈은 보통 JAR 파일, 컴포넌트는 WAR 파일이나 실행 가능한 JAR 파일입니다. 모듈 간 디펜던시와 컴포넌트/모듈 간 조합 관계도 이 뷰에 포함됩니다.

  • 프로세스 뷰: 런타임 컴포넌트. 각 엘리먼트는 개별 프로세스고, IPC는 프로세스 간 관계를 나타냅니다.

  • 배포 뷰: 프로세스가 머신에 매핑되는 방법. 이 뷰의 엘립먼트는 머신 및 프로세스고, 머신 간의 관계가 바로 네트워킹입니다. 프로세스와 머신 사이의 관계도 이 뷰에서 기술됩니다

아키텍처 스타일 개요

아키텍처 스타일은 체계적인 조직 관점에서 시스템 군을 정의한다.

아키텍처 스타일은 그 스타일로 만든 인스턴스에서 사용 가능한 컴포넌트와 커넥터의 용어집, 그리고 이들을 조합할 수 있는 제약 조건을 결정한다.

계층화 아키텍처 스타일

  • 계층마다 명확히 정의된 역할을 분담하며, 계층 간 디펜던시는 아키텍처로 제한

  • 어떤 계층은 바로 하위에 있는 계층에만 의존하거나, 하위에 위치한 어느 한 계층에 의존

  • 3계층 아키텍처

    • 표현 계층: 사용자 인터페이스 또는 외부 API가 구현된 계층

    • 바즈니스 로직 계층: 비즈니스 로직이 구현된 계층

    • 영속화 계층: DB 상호 작용 로직이 구현된 계층

  • 계층화 아키텍처의 문제점

    • 표현 계층이 하나뿐이다.

    • 영속화 계층이 하나뿐이다.

    • 비즈니스 로직 계층을 영속화 계층에 의존하는 형태로 정의한다.

육각형 아키텍처 스타일

  • 논리 뷰를 비즈니스 로직 중심으로 구성하는 계층화 아키텍처 스타일의 대안

  • 비즈니스 로직에는 하나 이상의 포트(자바라면 인터페이스)가 존재하고 포트 종류는 인바운드/아웃바운드 두 가지

    • 인바운드 포트: 비즈니스 로직이 표출된 API로 외부 애플리케이션은 이 API를 통해 비즈니스 로직을 호출(ex. 서비스 인터페이스)

    • 아웃바운드 포트: 비즈니스 로직이 외부 시스템을 호출하는 방법에 관한 것(ex. 리포지토리 인터페이스)

  • 어댑터도 포트처럼 인바운드/아웃바운드 두 종류가 존재

    • 인바운드 어댑터: 외부에서 들어온 요청을 인바운드 포트를 호출해서 처리(ex. MVC Controller, Message Broker Client)

    • 아웃바운드 어댑터: 비즈니스 로직에서 들어온 요청을 외부 애플리케이션/서비스를 호출해서 처리(ex. DAO Class, Proxy Class, 이벤트 발행)

  • 육각형 아키텍처 스타일의 가장 큰 장점은 비즈니스 로직에 있던 표현/데이터 접근 로직이 어댑터와 분리되었기 때문에 비즈니스 로직이 표현/데이터 접근 로직 어디에도 의존하지 않는다는 점

    • 비즈니스 로직만 따로 테스트하기 쉽고, 현대 애플리케이션 아키텍처(마이크로서비스)를 좀 더 정확하게 반영 가능

마이크로서비스 아키텍처는 일종의 아키텍처 스타일이다

모놀리식 아키텍처: 애플리케이션을 실행/배포 가능한 단일 컴포넌트로 구성한 아키텍처 스타일

마이크로서비스 아키텍처: 애플리케이션을 느슨하게 결합된, 독립적으로 배포 가능한 여러 서비스로 구성한 아키텍처 스타일

.

서비스?

  • 어떤 기능이 구현되어 단독 배포가 가능한 소프트웨어 컴포넌트

  • 클라이언트가 자신이 서비스하는 기능에 접근할 수 있도록 커맨드, 쿼리, 이벤트로 구성된 API를 제공

  • 서비스 API는 내부 구현 상세를 캡슐화

  • 대부분 육각형 아키텍처 형태

.

느슨한 결합

  • 서비스 구현 코드를 감싼 API를 통해서만 상호작용하므로 클라이언트에 영향을 끼치지 않고 서비스 내부 구현 코드를 바꿀 수 있다.

  • 유지보수성, 테스트성을 높이고 애플리케이션 개발 시간을 단축하는 효과가 있다.

  • 개발자가 서비스를 이해하고, 변경하고, 테스트하기 더 쉽다.

.

공유 라이브러리의 역햘

  • 서비스 코드 중복을 줄이는 것은 좋지만 의도치 않은 서비스 간 결합도를 유발하지 않도록 주의가 필요

  • 바뀔 일이 거의 없는 기능은 라이브러리에 담아 쓰는 것이 좋음

.

서비스 규모는 별로 중요하지 않다

  • 크기보다는 작은 팀이 가장 짧은 시간에, 다른 팀과 협동하는 부분은 최소로 하여 개발 가능한 서비스를 설계해야 함

  • 마이크로서비스 아키텍처는 작고, 느ㄴ하게 결합된 서비스로 애플리케이션을 구성하기 때문에 유지보수성, 테트성, 배성 등 개발 단계의 품질 속성이 개선

  • 조직 차원에서 소프트웨어를 더 빨리 개발할 수 있고, 주된 목표는 아니지만 애플리케이션 확장성도 향상

마이크로서비스 아키텍처 정의

애플리케이션의 마이크로서비스 아키텍처를 정의하는 3단계 프로세스

  • 아키텍처를 정의하는 1단계는 애플리케이션 요건을 핵심 요청으로 추출하는 것-

  • 2단계는 어떻게 여러 서비스로 분해할지 결정하는 것

  • 3단계는 서비스별로 API를 정의하는 것

분해 과정에서의 장애물

  • 네트워크 지연

    • 서비스 간 왕봑이 너무 잦아 실제로 분해할 수 없는 경우

  • 서비스 간 동기 통신으로 인해 가용성이 떨어지는 문제

    • 자기 완비형 서비스로 해결

  • 여러 서비스에 걸쳐 데이터 일관성을 지키는 요건

    • 보통 사가 패턴으로 해결

  • 애플리케이션 도처에 숨어 있는 만능 클래스

    • 이런 클래스는 DDD 개념을 활용하면 어렵지 않게 제거 가능

시스템 작업 식별

애플리케이션 아키텍처를 정의하는 첫 단추는 시스템 작업을 정의하는 일

  • 1단계: 시스템 작업을 기술하기 위해 필요한 보케블러리를 제공하는 핵심 클래스로 구성된 고수준의 도메인 모델 생성하기

  • 2단계: 시스템 작업 식별 후 그 동작을 도메인 모델 관점에서 기술하기

.

고수준 도메인 모델 생성

  • 도메인 모델은 스토리에 포함된 명사를 분석하고 도메인 전문가와 상담하는 등 표준 기법을 활용하여 생성

    • 사용자 시나리오에 포함된 명사를 통해 Consumer, Order, Restaurant, CreditCard 등 다양한 클래스가 필요할 것을 확인

Given
  소비자가 있다.
  음식점이 있다.
  음식점은 소비자의 주소로 제시간에 음식을 배달할 수 있다.
  주문 총액이 음식점의 최소 주문량 조건에 부합한다.

When
  소비자가 음식점에 음식을 주문한다.

Then
  소비자 신용카드가 승인된다.
  주문이 PENDING_ACCEPANCE 상태로 생성된다.
  생성된 주문이 소비자와 연관된다.
  생성된 주문이 음식점과 연관된다.

배달 서비스 도메인 모델의 주요 클래스

.

시스템 작업 정의

  • 애플리케이션이 어떤 요청을 처리할지 식별하는 단계

  • 시스템 작업은 크게 두 종류로 나뉨

    • Command: 데이터 생성, 수정, 삭제

    • Query: 데이터 읽기

  • 시스템 커맨드를 식별하려면 사용자 스토리/시나리오에 포함된 동사를 먼저 분석

배달 애플리케이션의 주요 시스템 커맨드

createOrder() 시스템 작업의 명세 정의

  • 선행 조건은 주문하기 시나리오의 전제(given)를, 후행 조건은 주문하기 시나리오의 결과(then)

고수준 도메인 모델과 시스템 작업을 보면 애플리케이션이 무슨 일을 하는지 알 수 있기 떄문에 아키텍처를 정의하는 데 대단히 유용

  • 시스템 작업을 정의한 후에는 애플리케이션 서비스를 식별

서비스 정의: 비즈니스 능력 패턴별 분해

마이크로서비스 아키텍처를 구축하는 첫 번째 전략은 비즈니스 능력에 따라 분해하는 것

  • 비즈니스 능력은 비즈니스가 가치를 생산하기 위해 하는 일을 말함.

  • 보험 회사라면 증권 인수, 클레임 관리, 과금, 컴플라이언스 등의 능력

  • 온라인 쇼핑물이라면 주문 관리, 재고 관리, 선적 등의 능력

.

비즈니스 능력은 곧 조직이 하는 일이다.

  • 비즈니스 능력을 보면 그 조직의 비즈니스가 무엇인지 알 수 있다.

.

비즈니스 능력 식별

  • 한 조직의 비즈니스 능력은 조직의 목표, 구조, 비즈니스 프로세스를 분석하여 식별

  • 비즈니스 능력은 보통 특정 비즈니스 객체에 집중하며, 여러 개의 하위 능력으로 분해할 수 있음

  • 클레임이라는 비즈니스 객체는 클레임 관리 능력을 중심으로 클레임 정보 관리, 클레임 검토, 클레임 지불 관리 등의 하위 능력이 있음

.

비즈니스 능력을 여러 서비스로

  • 비즈니스 능력을 식별한 후 능력에 따라 또는 연관된 능력 그룹에 따라 서비스를 정의

배달 서비스로 보면 다양한 수준의 비즈니스 능력이 여러 서비스로 매핑

서비스를 거의 변하지 않는 비즈니스 능력에 따라 구성하면 비교적 안정적인 아키텍처를 구축 가능

서비스 정의: 하위 도메인 패턴별 분해

DDD에는 마이크로서비스 아키텍처에 적용하면 정말 유용한 하위 도메인과 경계 컨텍스트 개념이 있음

  • DDD는 도메인을 구성하는 각 하위 도메인마다 도메인 모델을 따로 정의

  • 배달 서비스의 하위 도메인은 주문 접수, 주문 관리, 주방 관리, 배달, 재무 등

  • 도메인 모델의 범위를 DDD용어로는 경계 컨텍스트라고 함

하위 도메인을 서비스에 매핑 (각 하위 도메인은 자체 도메인 모델을 가진 서비스로 매핑)

분해 지침

단일 책임 원칙

  • 클래스는 오직 하나의 변경 사유를 가져야 한다.

  • 이 원칙을 마이크로서비스 아키텍처에 적용하면 하나의 책이만 가진 작고 응집된 서비스를 정의할 수 있다.

공동 폐쇄 원칙(CCP)

  • 패키지의 클래스들은 동일한 유형의 변경에 대해 닫혀 있어야 한다. 패키지에 영향을 주는 변경은 그 패키지에 속한 모든 클래스에 영향을 끼친다.

  • 어떤 두 클래스가 동일한 사유로 맞물려 변경되면 동일한 패키지에 있어야 한다.

서비스 분해의 장애물

서비스 분해의 장애 요소

  • 네트워크 지연

  • 동기 통신으로 인한 가용성 저하

  • 여러 서비스에 걸쳐 데이터 일관성 유지

  • 데이터의 일관된 뷰 확보

  • 분해를 저해하는 만능 클래스

네트워크 지연

  • 분산 시스템의 고질적인 문제

  • 한 차례 왕복으로 여러 객체를 한 번에 가져오는 배치 API를 구현하거나, 값비싼 IPC를 언어 수준의 메서드나 함수 호출로 대체하는 식으로 서비스 결합에 따른 지연 시간을 축소

동기 IPC로 인한 가용성 저하

  • 비동기 메시징으로 강한 결합도를 제거하고 가용성을 높이는 방법이 존재

여러 서비스에 걸쳐 데이터 일관성 유지

  • 사가라는 전혀 다른 방식으로 트랜잭션을 관리해야 함

    • 사가는 메시징을 이용한 일련의 로컬 트랜잭션

  • 한 가지 단점은 최종 일관성을 보장한다는 것인데,

    • 어떤 데이터를 원자적으로 업데이트해야 한다면 그 데이터를 하나의 서비스 내부에 두어야 하는데, 이는 결국 분해의 걸림돌이 된다.

일관된 데이터 뷰 확보

  • 어떤 데이터를 일관된 뷰로 바라보려면 하나의 서비스 내부에 두어야 하는데, 이 역시 분해의 걸림돌

.

만능 클래스느 분해의 걸림돌

  • 만능 클래스는 애플리케이션의 여러 측면의 상태/동작을 보이지 않게 감싸고 있기 때문에 이 클래스를 사용하는 전체 비즈니스 로직을 서비스로 분리하려면 골치가 아픕니다.

가장 좋은 방법은 DDD를 적용하여 각 서비스를 자체 도메인 모델을 갖고 있는 개별 하위 도메인으로 취급하는 것

  • Order 대신 Delivery라는 더 적절한 이름의 모델을 사용

배달 서비스 도메인 모델

주방 서비스 도메인 모델

주문 서비스 도메인 모델

이런 서비스 간 일관성은 이벤트 주도 메커니즘인 사가(4장)를 활용해서 유지 가능

  • UX 구현 시에는 소비자가 조회한 주문 상태는 여러 서비스에 저장된 Order 정보에서 비롯된 것이므로 보통 API 게이트웨이를 통해 처리(8장)

서비스 API 정의

서비스 API 작업은 외부 클라이언트 또는 타 서비스가 호출하는 시스템 작업과 서비스 간 협동을 지원하기 위해 타 서비스 호출 전용으로 만든 작업, 둘 중 하나입니다.

.

시스템 작업을 서비스로 배정

  • 어떤 작업이 제공하는 정보가 필요한 서비스에 그 작업을 배정하는 것이 더 합리적

시스템 작업을 애플리케이션 서비스에 매핑

서비스 간 협동 지원에 필요한 API 확정

  • 서비스 API를 온전하게 정의하려면 각 시스템 작업을 면밀히 분석해서 서로 어떻게 협동해야 할지 결정해야 한다.

여러 서비스가 서로 협동하는 방식에 영향을 미치는 아키텍처/설계 개념

  • (3장) REST 같은 동기 통신 메커니즘, 메시지 브로커를 이용한 비동기 메시징 등 구체적인 IPC 기술

    • 주문 서비스는 음식점 서비스 데이터의 레플리카를 갖게 되어 일일이 음식점 서비스를 동기 호출해서 주문이 올바른지 확인할 필요가 있음

  • (4장) 사가 개념에 대해 소개하고 사가에 참여한 서비스를 조정하는 비동기 메시징의 활용 방법 설명

    • 사가는 여러 서비스에 흩어진 데이터를 확실하게 업데이트하고 자기 완비형 서비스를 구현하는 수단

  • (8장) API를 외부 클라이언트에 표출하는 API 게이트웨이 개념을 다룹니다

    • API 게이트웨이는 단순히 요청을 서비스로 넘기는 것뿐만 아니라 API 조합 패턴을 이용해서 쿼리 작업도 수행

마치며

  • 아키텍처는 애플리케이션 개발 속도에 직접 영향을 주는 갖가지 '~성`을 좌우

  • 마이크로서비스 아키텍처는 애플리케이션의 관리성, 테스트성, 배포성을 높이는 아키텍처 스타일

  • 마이크로서비스는 기술적 관심사보다 비즈니스 능력, 하위 도메인 등 비즈니스 관심사 위주로 구성

  • 서비스를 분해하는 패턴은 크게 두 가지

    • 비즈니스 능력에 따른 분해: 비즈니스 아키텍처 기반

    • 하위 도메인에 따른 분해: DDD 개념 기반

  • DDD를 적용하고 서비스마다 도메인 모델을 따로 설계하면, 의존 관계가 뒤엉켜 분해를 가로막는 만능 클래스를 제거할 수 있음

Last updated