한 줄 정의

마이크로서비스 아키텍처

DDD의 경계 컨텍스트(bounded context) 를 물리적 토폴로지로 그대로 옮겨, 각 서비스가 자기 도메인에 필요한 코드와 데이터, 의존요소를 모두 보유 한 채 개별 프로세스로 실행되는 무공유(share nothing) 분산 아키텍처 입니다. 재사용보다 중복을 우선하는 극단적 분리 철학이 핵심입니다.

쉽게 말하면

“하나의 큰 시스템을 도메인 단위로 잘게 쪼개고, 각 조각이 자기만의 코드와 자기만의 데이터베이스 를 갖고 살게 하자”는 발상입니다. 마틴 파울러와 제임스 루이스가 2014년 블로그 게시물에서 이름을 붙이면서 유명해졌고, SOA가 추구한 전체론적 재사용의 반대편에 섭니다.

경계 컨텍스트가 핵심 영감

DDD의 경계 컨텍스트(bounded context) 개념이 이 아키텍처에 결정적인 영감을 주었습니다. 한 컨텍스트 안에서는 코드와 데이터 스키마 같은 내부 구성요소가 자유롭게 결합되어도 되지만, 다른 컨텍스트에 속한 데이터베이스나 클래스 정의와는 절대 결합하지 않습니다. 그래서 마이크로서비스를 무공유(share nothing) 아키텍처라고도 부릅니다.

재사용 대신 중복을 택한다

도메인을 정의할 때는 코드나 데이터베이스 스키마 같은 요소로 식별되는 수많은 엔티티와 행동방식(behavior)이 포함됩니다. CatalogCheckout이라는 도메인이 있다면 카탈로그 아이템, 고객, 결제 같은 개념이 들어가게 됩니다. 전통적인 모놀리스에서는 이런 개념을 재사용 가능한 클래스와 공유 데이터베이스로 묶어서 처리하는 게 자연스러웠습니다.

마이크로서비스는 이 기본 가정을 뒤집습니다. 재사용에는 항상 상속이나 조합 이 따라오고, 그 순간 시스템의 결합도가 올라갑니다. 그래서 고도로 분리된(decoupled) 시스템 을 만들고 싶다면 재사용보다 중복(duplication) 을 선호하고, 경계 컨텍스트를 물리적으로 모델링해서 서비스와 그에 상응하는 데이터를 한 덩어리로 묶어 배포 합니다.

핵심 트레이드오프

마이크로서비스는 “재사용 = 좋은 것”이라는 통념을 거부합니다. 분리 자체가 목표 이고, 그 목표를 이루기 위해서라면 약간의 코드 중복은 기꺼이 받아들입니다. 이 가치 판단을 받아들이지 못하면 마이크로서비스는 결국 분산 모놀리스 로 귀결됩니다.

왜 이렇게 설계했는가?

  • 해결하는 문제: SOA에서 드러난 공유 데이터베이스·중앙 오케스트레이션 엔진의 결합 폭발, 그리고 멀티테넌트 인프라에서 발생하는 자원 한계와 격리 실패 문제입니다. 모놀리스의 단순한 재사용 모델이 현실에서는 변경 비용 폭발로 이어진 경험에서 출발했습니다.
  • 이게 없다면: 모든 도메인이 같은 애플리케이션 서버와 같은 데이터베이스를 공유합니다. 한 도메인의 트래픽 폭증이 전체 인프라 자원을 잠식하고, 한 모듈의 장애가 같은 프로세스의 다른 모듈로 번집니다. 도메인 변경 한 건이 전사 차원의 협의 로 번지는 SOA식 결합이 그대로 재현됩니다.
클라우드·컨테이너 기술이 만든 새로운 전제

도메인마다 인프라를 따로 두는 접근법은 오픈소스 운영체제와 자동화된 머신 프로비저닝(provisioning) 기술이 발전하기 전에는 비현실적 이었습니다. 도메인 수만큼 서버 라이선스와 운영 인력이 필요했기 때문입니다.

이제는 클라우드 자원과 컨테이너 기술 덕분에 도메인 수준과 운영 수준 모두에서 극단적인 분리 가 현실적인 선택지가 되었습니다. 마이크로서비스가 2010년대 이후에야 주류로 떠오른 것은 우연이 아닙니다.

토폴로지

flowchart TB
    C1[클라이언트 요청] --> API
    C2[클라이언트 요청] --> API
    C3[클라이언트 요청] --> API
    API["API 계층"]
    API --> S1 & S2 & S3 & S4 & S5
    subgraph S1["서비스"]
        direction TB
        M1["모듈 + 모듈"]
        DB1[("DB")]
        M1 --- DB1
    end
    subgraph S2["서비스"]
        direction TB
        M2["모듈"]
        DB2[("DB")]
        M2 --- DB2
    end
    subgraph S3["서비스"]
        direction TB
        M3["모듈"]
        DB3[("DB")]
        M3 --- DB3
    end
    subgraph S4["서비스"]
        direction TB
        M4["모듈"]
        DB4[("DB")]
        M4 --- DB4
    end
    subgraph S5["서비스"]
        direction TB
        M5["모듈"]
        DB5[("DB")]
        M5 --- DB5
    end

토폴로지를 한눈에 보면 두 가지가 두드러집니다.

첫째, 서비스가 다른 분산 아키텍처들보다 훨씬 작습니다. 둘째, 각 서비스가 자기 데이터베이스를 끼고 있습니다.

다른 분산 아키텍처보다 훨씬 작은 서비스

마이크로서비스의 서비스는 오케스트레이션 주도 SOA, 이벤트 주도 아키텍처, 서비스 기반 아키텍처의 서비스보다 덩치가 훨씬 작습니다. 서비스가 단일 목적을 갖도록 의도적으로 잘게 쪼개고, 그 안에 독립적으로 작동하는 데 필요한 모든 부분(데이터베이스와 기타 의존요소)을 포함시킵니다.

아키텍처서비스 단위데이터 소유
Ch14 서비스 기반 아키텍처도메인 서비스 (수 개~수십 개)단일 또는 분리 가능한 DB
Ch15 이벤트 주도 아키텍처이벤트 프로세서공유 또는 분리
Ch17 오케스트레이션 주도 서비스 지향 아키텍처비즈니스/엔터프라이즈 서비스단일·소수 DB 공유
마이크로서비스단일 목적의 작은 서비스 (수십~수백 개)서비스마다 독립 DB

분산 + 컨테이너/VM 기반 실행

각 서비스는 VM이나 컨테이너 안에서 개별 프로세스로 실행 됩니다. 이 정도로 분리하면 멀티테넌트 인프라에서 흔히 보이는 두 가지 문제를 동시에 해결합니다.

자원 한계 문제

여러 애플리케이션이 하나의 애플리케이션 서버를 공유하면 네트워크 대역폭, 메모리, 디스크 같은 운영 자원을 재사용할 수 있어 효율적으로 보입니다. 하지만 지원하는 모든 애플리케이션의 규모가 계속 커지면 결국 공유 인프라의 특정 자원이 한계에 부딪힙니다. 한 서비스가 한 프로세스로 분리되면 자기 자원만 쓰고, 한계에 닿더라도 그 서비스만 스케일하면 됩니다.

격리 실패 문제

공유 환경에서는 한 애플리케이션의 메모리 누수나 무한 루프가 같은 프로세스의 다른 애플리케이션을 끌어내립니다. 개별 프로세스로 분리하면 이 격리 문제가 자동으로 해결 됩니다. 컨테이너 단위로 죽고 살기 때문입니다.

분산이 강요하는 비용 — 성능과 트랜잭션

마이크로서비스가 가져오는 분리는 공짜가 아닙니다.

네트워크 호출 비용

분산 아키텍처는 성능이 단점으로 꼽힐 때가 많습니다. 두 가지 이유가 누적됩니다.

  • 네트워크 호출은 같은 프로세스 내 메서드 호출보다 훨씬 오래 걸립니다.
  • 모든 종단점(endpoint)에서 보안을 검사 해야 하므로 호출마다 처리 시간이 더 늘어납니다.

그래서 서비스 사이의 호출이 많으면 처리량이 빠르게 떨어집니다.

트랜잭션 경계 — 넘으면 안 된다

숙련된 아키텍트들은 입을 모아 서비스 경계(service boundary)를 넘나드는 트랜잭션을 쓰지 말라 고 조언합니다. 분산 환경에서 강한 ACID 트랜잭션을 강제하면 결국 SOA가 겪었던 분산 트랜잭션의 악몽으로 되돌아갑니다.

세분도(granularity)가 성패를 가른다

성능과 트랜잭션 양쪽 모두에서, 결정적인 요인은 서비스를 얼마나 잘게 쪼개느냐 입니다.

  • 너무 잘게 쪼개면 → 네트워크 호출이 폭증하고 트랜잭션 경계를 자꾸 넘게 됩니다.
  • 너무 크게 묶으면 → 모놀리스의 결합 문제가 다시 살아납니다.

마이크로서비스의 진짜 어려움

서비스의 세분도를 잘 결정하는 것이야말로 이 아키텍처의 성패를 가르는 관건 입니다. 토폴로지가 단순해 보여도, 실제 설계의 90%는 “이걸 한 서비스로 묶을지 두 개로 쪼갤지”를 판단하는 데 들어갑니다.

핵심 내용

경계 컨텍스트 — 함수, 하위 도메인, 또는 작업흐름 단위

각 서비스는 특정 하나의 기능(function), 하위 도메인, 또는 작업흐름(workflow) 을 모델링합니다. 그 안에는 해당 기능이 작동하는 데 필요한 모든 것 이 들어갑니다.

구성요소의미
논리적 컴포넌트와 클래스로 구성된 서비스비즈니스 로직
데이터베이스 스키마데이터 모델
서비스가 사용하는 데이터베이스영속성

각 서비스는 특정 하위 도메인이나 기능을 대표하는 요소 로 간주됩니다. 다시 말해 마이크로서비스의 한 인스턴스는 도메인의 한 조각을 통째로 책임지는 단위입니다.

Address 공통 클래스의 운명

모놀리스에서 개발자는 흔히 Address 같은 공통 클래스를 만들어 시스템 전반에서 공유합니다. 마이크로서비스에서는 이게 죄악 입니다. 결합을 피하는 것이 핵심 가치이므로, 아키텍트는 결합 대신 중복 을 택해서 모든 코드를 해당 경계 컨텍스트 안에 가둡니다. 같은 Address 코드가 여러 서비스에 반복 등장하더라도, 그것이 경계를 넘는 결합보다 낫다는 판단입니다.

DDD의 물리적 구현

마이크로서비스는 도메인 분할의 개념을 극단까지 밀어붙입니다. 여러 면에서 이 아키텍처는 DDD의 논리적 개념을 물리적으로 구현한 것 이라고 할 수 있습니다. 경계 컨텍스트라는 추상이 곧 컨테이너 한 개와 데이터베이스 한 개로 떨어집니다.

세분도(granularity) — 마이크로서비스의 진짜 어려움

마이크로서비스 설계에서 가장 자주 빠지는 함정은 마이크로 라는 글자 그대로 받아들여 서비스를 너무 작게 만드는 것입니다. 그 결과 유용한 작업을 위해 서비스 사이에 통신 링크를 다시 잔뜩 구축 해야 하고, 결국 만들어지는 것은 분산된 진흙잡탕(Big Ball of Distributed Mud) 입니다.

마이크로서비스라는 용어는 이름표(label)이지 설명(description)이 아니다. — 마틴 파울러

파울러와 루이스가 2007년경 지배적이던 거대 서비스(gigantic service) SOA와 대비시키려 붙인 이름이지, “최대한 잘게 쪼개라”는 계명은 아닙니다.

적절한 경계를 찾는 세 가지 지침
지침핵심 질문의미
목적이 서비스는 어떤 비즈니스 행동방식에 기여하는가?가장 명백한 기준. 문제 도메인에 따라 결정. 기능적 응집력을 가져야 함
트랜잭션이 엔티티들은 트랜잭션에서 협력해야 하는가?함께 트랜잭션해야 하는 엔티티는 좋은 서비스 경계를 암시. 분산 트랜잭션을 피하는 방향이 더 나은 설계
코레오그래피 방식서비스끼리 통신량이 너무 많아지지 않는가?코레오그래피로 풀려면 통신량이 폭증할 때, 더 큰 서비스로 묶는 것을 검토
반복이 유일한 방법

좋은 서비스를 설계하려면 반복이 유일한 방법 입니다. 첫 시도에서 세분도, 데이터 의존성, 통신 스타일을 완벽하게 결정하는 경우는 드뭅니다. 시스템과 비즈니스 기능을 더 알게 되면서 반복적으로 개선해 나갑니다. 마이크로서비스 도입 6개월 후 서비스 경계를 다시 그리는 일은 실패가 아니라 정상 입니다.

데이터 격리 — 단일 진실 공급원의 종말

영속성을 위해 단일 데이터베이스를 쓰는 아키텍처가 많지만, 마이크로서비스는 모든 종류의 결합을 피하려 노력 하므로 공유 스키마와 데이터베이스를 통합 지점으로 사용하는 것 도 그 결합에 포함됩니다.

엔티티 함정(Entity Trap) 경계

서비스를 DB의 개별 엔티티들과 유사하게 모델링하는 실수 를 범하지 말아야 합니다. Customer 테이블이 있다고 Customer 마이크로서비스를 만드는 식의 1:1 매핑은 SOA의 보험회사 사례를 그대로 답습합니다. 서비스 경계는 비즈니스 작업흐름 을 따라 그어야지 데이터 모델을 따라 그어선 안 됩니다.

단일 진실 공급원의 종말

관계형 DB를 써서 단일 진실 공급원(single source of truth) 을 만드는 데 익숙하지만, 데이터를 분산하면 그 방법은 통하지 않습니다. 모든 아키텍트는 둘 중 하나를 택해야 합니다.

선택지방식트레이드오프
도메인 진실 공급원 + 협력 호출사실(fact)에 대한 진실 공급원이 될 만한 도메인 하나를 식별하고, 다른 서비스가 호출해서 값을 조회결합도 약간 발생, 네트워크 호출 비용
DB 복제 또는 캐싱정보를 여러 서비스에 분산시켜 각자 보유데이터 정합성과 동기화 부담
격리가 가져온 자유

이 수준의 데이터 격리는 골칫거리이자 기회 입니다. 단일 DB를 중심으로 통합할 필요가 없어지므로, 팀마다 자기 서비스의 예산·저장 구조 유형·운영 특성에 가장 적합한 DB 기술을 자유롭게 선택 할 수 있습니다. 또한 어떤 팀이든 다른 팀에 영향을 주지 않고 기존 DB를 더 적합한 것으로 언제든 교체 할 수 있습니다. 다른 팀이 그 구현 세부사항에 결합되는 것 자체가 허용되지 않기 때문입니다.

API 계층 — 게이트웨이는 중재자가 아니다

대부분의 마이크로서비스 아키텍처는 시스템의 소비자(UI 또는 다른 시스템)와 마이크로서비스 사이에 흔히 API 게이트웨이(API Gateway) 라고 부르는 API 계층을 둡니다. 단순한 역방향 프록시(reverse proxy) 일 수도 있고, 보안이나 명명 서비스(naming service) 같은 횡단 관심사(cross-cutting concern) 를 포함하는 정교한 게이트웨이일 수도 있습니다.

API 계층은 중재자/오케스트레이터가 아니다

이 아키텍처의 기본 철학에 충실하려면 API 계층을 중재자(mediator)나 오케스트레이터(orchestrator)로 사용해서는 안 됩니다. 모든 흥미로운 비즈니스 로직은 경계 컨텍스트 안에 있어야 합니다. 오케스트레이션이나 비즈니스 로직을 중재자에 넣는 순간 SOA의 ESB가 부활합니다.

API 계층에는 요청 라우팅·보안·모니터링·로깅 같은 횡단 관심사만 포함합니다. 비즈니스 관련 로직은 절대 들이지 않습니다.

운영 재사용 — 사이드카와 서비스 메시

마이크로서비스는 결합보다 중복을 선호하지만, 모니터링·로깅·서킷 브레이커 같은 운영상 관심사 들은 결합이 오히려 도움이 됩니다. 도메인은 분리하되 운영 기능은 표준화 하고 싶은 욕구가 자연스럽게 생깁니다. 이 모순을 푸는 것이 사이드카(Sidecar) 패턴 입니다.

사이드카 패턴
flowchart TB
    subgraph S1["서비스"]
        D1["도메인 모듈들"]
        SC1["Sidecar<br/>서킷 브레이커 / 로깅<br/>모니터링 / ..."]
    end
    subgraph S2["서비스"]
        D2["도메인 모듈들"]
        SC2["Sidecar<br/>서킷 브레이커 / 로깅<br/>모니터링 / ..."]
    end
    DB1[(데이터베이스)]
    DB2[(데이터베이스)]
    S1 --- DB1
    S2 --- DB2

사이드카 컴포넌트 는 결합을 통해 이점을 얻는 모든 운영상 관심사를 처리합니다. 개별 팀이나 공유 인프라 팀이 소유할 수 있고, 모니터링 도구를 업그레이드할 때 공유 인프라 팀이 사이드카만 업그레이드하면 모든 마이크로서비스에 새 기능이 적용 됩니다.

서비스 메시(service mesh)와 서비스 평면

모든 서비스에 공통의 사이드카를 포함시키면, 서비스 메시(service mesh) 를 구축해서 팀들이 아키텍처 전반의 공통 관심사를 통합적으로 제어할 수 있습니다.

flowchart LR
    SC1[Sidecar 1] --- Plane["서비스 평면<br/>(service plane)"]
    SC2[Sidecar 2] --- Plane
    SC3[Sidecar 3] --- Plane
    SC4[Sidecar 4] --- Plane

서비스 평면(service plane) 은 일관된 인터페이스로 모든 사이드카를 연결해서 서비스 메시를 형성하는 통합 소프트웨어이고, 흔히 Istio 같은 제품 형태로 제공됩니다. 각 서비스는 전체 메시에서 하나의 노드가 되며, 메시는 모니터링 수준·로깅 등 운영상의 결합을 전역적으로 제어하는 콘솔 역할을 합니다.

서비스 발견(service discovery)

탄력성 구축 방법으로 서비스 발견(service discovery) 도 자주 도입됩니다. 네트워크에서 서비스를 자동 탐지하고 위치를 찾아주는 도구로, 적절한 서비스 인스턴스 탐색뿐 아니라 요청 수와 빈도 모니터링·확장성/탄력성 문제 처리를 위한 새 인스턴스 가동 까지 담당합니다. 보통 서비스 메시 또는 API 계층에 포함시킵니다.

프런트엔드 — 모놀리스 프런트엔드 vs 마이크로프런트엔드

마이크로서비스는 분리 를 선호하므로 이상적으로는 UI도 경계 컨텍스트의 일부여야 합니다. 그러나 웹 애플리케이션의 현실적 제약 때문에 두 가지 스타일로 나뉩니다.

모놀리스 프런트엔드(monolithic frontend)
flowchart TB
    UI["모놀리스 사용자 인터페이스"]
    UI --> API["API 계층"]
    API --> S1[서비스 1] & S2[서비스 2] & S3[서비스 3] & S4[서비스 4] & S5[서비스 5]

단일 UI가 사용자 요청을 API 계층을 통해 시스템에 보냅니다. 리치 데스크톱·모바일 앱·웹 애플리케이션 어느 형태든 가능합니다. 현재 많은 웹 앱이 자바스크립트 프레임워크로 단일 UI를 구축하는 방식이 여기에 해당합니다.

마이크로프런트엔드(micro-frontend)
flowchart TB
    subgraph MF["마이크로프런트엔드"]
        UI1[UI 컴포넌트] & UI2[UI 컴포넌트] & UI3[UI 컴포넌트] & UI4[UI 컴포넌트] & UI5[UI 컴포넌트]
    end
    MF --> API["API 계층"]
    UI1 --> S1[서비스 1]
    UI2 --> S2[서비스 2]
    UI3 --> S3[서비스 3]
    UI4 --> S4[서비스 4]
    UI5 --> S5[서비스 5]

프런트엔드를 여러 UI 컴포넌트로 구성하되, UI와 백엔드의 격리·세분도가 같은 수준이 되도록 작성합니다. UI 컴포넌트와 해당 백엔드 서비스 사이에 1:1 관계가 형성되며, 팀이 자기 도메인의 UI까지 끝까지 책임지는 풀 스택 도메인 팀 모델이 자연스럽게 가능해집니다.

더 깊이 알아보려면 루카 메잘리라(Luca Mezzalira)의 Building Micro-Frontends 2판(O’Reilly, 2025) 추천.

통신 — 동기/비동기와 프로토콜 인식 이기종 상호운용성

서비스 세분도는 데이터 격리와 통신 모두 에 영향을 미칩니다. 서비스가 분리된 상태로도 협력하려면 아키텍트는 올바른 통신 스타일을 결정해야 합니다.

동기 vs 비동기

기본 선택지는 동기적(synchronous) 통신과 비동기(asynchronous) 통신 두 가지입니다. 동기 통신은 송신자가 수신자의 응답을 기다려야 하는 방식이고, 비동기 통신을 위해서는 흔히 이벤트와 메시지 를 활용합니다(이 점은 이벤트 주도 아키텍처와 비슷합니다).

프로토콜 인식 이기종 상호운용성

마이크로서비스 통신을 정의하는 핵심 용어는 프로토콜 인식 이기종 상호운용성(protocol-aware heterogeneous interoperability) 입니다. 세 부분으로 나눠 보면 다음과 같습니다.

부분의미
프로토콜 인식중앙 통합 허브가 없으므로, 서비스가 다른 서비스를 호출할 때 어떤 프로토콜을 써야 하는지 스스로 알아내야 함. 일정 수준의 REST나 메시지 대기열을 표준으로 정해 둠
이기종서비스마다 서로 다른 기술 스택으로 작성될 수 있는 폴리글랏(polyglot) 환경 을 완벽 지원
상호운용성서비스가 서로 호출하는 것 자체. 메서드 호출보다는 트랜잭션 방식 호출은 선호하지 않지만, 협업과 정보 교환을 위한 호출은 흔함

강제된 이기종성

어느 마이크로서비스 선구자 아키텍트는 모바일 개인정보 관리 소프트웨어 팀에 모든 개발 팀이 서로 다른 기술 스택을 사용해야 한다 는 규칙을 발표했습니다. 한 팀이 자바, 다른 팀이 닷넷이면 실수로 클래스를 공유할 수 없다 는 노림수였습니다.

표준화하려는 일반적 거버넌스 정책과 정반대지만, 마이크로서비스의 목표는 “가장 복잡한 생태계”가 아니라 좁은 범위 문제에 맞는 올바른 규모의 기술 을 선택하는 것입니다. 모든 서비스에 산업용 RDB가 필요한 건 아닙니다.

코레오그래피와 오케스트레이션

마이크로서비스의 코레오그래피(choreography)EDA와 동일한 통신 스타일입니다. 코레오그래피형 아키텍처에는 중앙 조정자(coordinator)나 중재자(mediator)가 없습니다. 경계 컨텍스트 철학과 부합하며, 서비스 사이에 분리된 이벤트를 자연스럽게 구현하게 합니다.

코레오그래피 — 서비스끼리 직접 호출
flowchart TB
    User(["사용자<br/>'123번 고객의 찜 목록을 가져오세요'"])
    User --> API["API 계층"]
    API --> WishList[고객 찜 목록]
    WishList -- "get_name" --> Demo[고객 인구통계]
    Demo -- "Mark" --> WishList
    WishList --> User

CustomerWishList가 사용자 요청을 받았는데 필요한 모든 정보를 갖고 있지 않으면, 직접 CustomerDemographics(고객 인구통계)에 요청해서 정보를 채운 뒤 사용자에게 반환합니다. 중앙 조정자 없이 서비스끼리 협력합니다.

지역 중재자 — 오케스트레이션 서비스

전역 중재자는 없지만, 여러 서비스를 조정해야 할 때 아키텍트는 지역 중재자(localized mediator) 를 따로 만들 수 있습니다. 흔히 오케스트레이션 서비스 라 부르는 것이 이것입니다.

flowchart TB
    User(["사용자<br/>'123번 고객의 모든 데이터를 가져오세요'"])
    User --> API["API 계층"]
    API --> Report[ReportCustomerInformation]
    Report --> WishList[고객 찜 목록]
    Report --> Demo[고객 인구통계]

ReportCustomerInformation이라는 중재자 서비스가 사용자 요청을 받아 필요한 다른 서비스를 적절히 호출합니다. 조정 책임을 한 서비스에 모았기 때문에 다른 서비스들 사이의 결합은 줄어듭니다.

프런트 컨트롤러 패턴 — 코레오그래피의 함정

복잡한 작업흐름을 코레오그래피로 풀면, 처음 호출된 서비스가 자기 도메인 책임 외에 중재자 역할까지 떠맡는 경우가 생깁니다. 이를 프런트 컨트롤러(Front Controller) 패턴 이라 부릅니다. 명목상 코레오그래피지만 실제로는 한 서비스가 너무 많은 역할을 맡아 복잡성이 가중 됩니다.

트레이드오프
방식장점단점
코레오그래피마이크로서비스의 고도 분리 철학 유지오류 처리·조정 같은 일반적 문제가 더 복잡해짐. 작업흐름이 복잡하면 프런트 컨트롤러 함정에 빠짐
오케스트레이션조정을 한 서비스에 집중시켜 다른 서비스 영향 줄임. 복잡한 비즈니스 작업흐름 표현 용이중재자 서비스로 결합이 일부 발생. 도메인 작업흐름이 본질적으로 결합되어 있음

도메인 작업흐름은 본질적으로 결합되어 있는 경우가 많습니다. 아키텍트의 임무는 도메인과 아키텍처 양쪽 목표를 가장 잘 지원하는 방식으로 그 결합을 표현하는 방법 을 찾는 것입니다.

트랜잭션과 사가 패턴

마이크로서비스에서 데이터베이스도 아키텍처와 동일한 수준으로 분리되는 게 바람직합니다. 모놀리스에서 간단했던 원자성(atomicity) 이 분산 환경에서는 까다로운 문제가 됩니다.

”하지 마세요”가 최고의 조언

서비스 경계를 넘나드는 트랜잭션은 마이크로서비스의 핵심 분리 원칙을 위반 하고, 최악의 동적 동변성인 값 동변성 을 유발합니다.

트랜잭션이 필요하다고 느낀다면

서비스 간 트랜잭션을 원하는 아키텍트에게 줄 수 있는 최고의 조언은 “하지 마세요!” 입니다. 대신 서비스 세분도를 조율 하는 것이 낫습니다. 마이크로서비스 아키텍처를 트랜잭션들로 엮어야 할 필요성을 자주 느낀다면, 그것은 설계가 너무 세분화되었다는 신호 입니다.

사가(Saga) 패턴

그래도 트랜잭션이 어쩔 수 없다면 사가(Saga) 패턴 을 씁니다. 문학에서 사가는 영웅적인 결말로 이어지는 긴 일련의 사건을 묘사하는 서사시인데, 패턴 이름도 거기서 유래했습니다.

sequenceDiagram
    participant U as 사용자
    participant API as API 계층
    participant M as 중재자 서비스
    participant CP as 고객 프로필
    participant CW as 신용카드 지갑
    U->>API: "새 고객을 등록하세요"
    API->>M: 1. 등록 요청
    M->>CP: 2. 고객 프로필 생성
    CP-->>M: 3. 성공
    M->>CW: 4. 신용카드 등록
    CW-->>M: 5. 실패
    M->>CP: 6. 보상(undo) — 프로필 삭제
    M-->>U: 7. 등록 실패 응답

중재자가 트랜잭션 각 부분을 호출하고, 성공/실패를 기록하고, 결과를 조정합니다. 모두 성공하면 동기적으로 업데이트되고, 어느 부분이 실패하면 다른 모든 부분도 트랜잭션 이전 상태로 되돌립니다.

보상 트랜잭션 프레임워크(compensating transaction framework)

이미 성공한 다른 모든 서비스에 이전 요청을 취소(undo)하라는 요청 을 보내는 방식을 보상 트랜잭션 프레임워크라고 부릅니다. 보통 중재자로부터 온 각 요청을 중재자가 전체 성공을 알릴 때까지 보류(pending) 상태로 두는 방식으로 구현합니다.

어려움양상
비동기 요청 조율보류 중인 트랜잭션 상태에 따라 달라지는 새 요청이 들어오면 처리가 복잡
네트워크 트래픽어떤 프로토콜이든 보상 트랜잭션은 네트워크 수준에서 조정 트래픽을 많이 유발

핵심 원칙

몇몇 트랜잭션이 어쩔 수 없이 서비스 경계를 넘는 경우는 종종 있습니다. 하지만 그런 경우가 아키텍처의 지배적인 특징이 될 정도로 빈번하다면, 마이크로서비스가 올바른 선택이 아닐 가능성이 높습니다.

데이터 토폴로지 — 서비스당 데이터베이스(Database-per-Service)

데이터 분리가 필수 인 아키텍처 스타일은 마이크로서비스가 유일합니다. 다른 분산 아키텍처에서는 모놀리스 DB가 (효과적이지 않더라도) 가능한 선택이지만, 마이크로서비스에서는 아예 선택지가 아닙니다. 도메인 범위 DB조차 허용되지 않는데, 마이크로서비스의 세밀한(fine-grained) 성질과 경계 컨텍스트, 그리고 생태계에 존재하는 수많은 서비스 때문입니다.

모놀리스 DB가 마이크로서비스와 결합되면

60개 서비스가 동일 DB를 공유한다고 상상해 보세요. 컬럼명을 바꾸거나 테이블을 삭제하면 60개 서비스 모두를 동시에 변경·테스트·배포 해야 합니다. 좋게 말해도 끔찍하고, 대형 사고로 이어질 가능성이 높습니다.

문제양상
변경 제어 불가DB 스키마 변경 시 모든 사용 서비스의 동시 배포 필요
물리적 경계 컨텍스트 붕괴데이터 구조도 경계 컨텍스트의 일부인데, DB를 공유하면 경계 컨텍스트가 사라짐
확장성/탄력성 불균형서비스 인스턴스는 자동 확장되지만 그에 맞춰 적절히 확장되는 DB는 드묾
DB 연결 고갈마이크로서비스는 일반적으로 각 서비스 인스턴스 마다 연결 보유. 인스턴스가 늘면 연결 풀 고갈
단일 장애점DB 다운 시 전체 마이크로서비스 생태계 중단
서비스당 데이터베이스 패턴
flowchart TB
    S1[서비스 1] --- DB1[(DB 1)]
    S2[서비스 2] --- DB2[(DB 2)]
    S3[서비스 3] --- DB3[(DB 3)]
    S4[서비스 4] --- DB4[(DB 4)]
    S5[서비스 5] --- DB5[(DB 5)]
    S6[서비스 6] --- DB6[(DB 6)]

각 마이크로서비스가 자신만의 데이터를 별도 DB나 스키마 안의 테이블 로 소유합니다. 다른 서비스가 그 데이터를 필요로 하면 반드시 계약을 통해 소유자 서비스에 요청 해야 합니다.

이 토폴로지의 가장 큰 미덕은 DB 변경의 영향이 소유자 서비스에만 한정 된다는 점입니다. 한 팀이 RDB를 문서 DB로 갈아 끼우더라도 다른 팀에 물어볼 필요가 없습니다.

예외: 5~6개 이내 서비스의 DB 공유
flowchart TB
    subgraph BC["경계 컨텍스트"]
        S1[결제·신용카드] & S2[결제·페이팔] & S3[결제·기프트카드] --- SharedDB[(공유 DB)]
    end

둘 이상의 서비스가 동일 테이블에 데이터를 기록해야 하거나, 성능상 외부에서 직접 쿼리해야 한다면 5~6개 이내 서비스가 하나의 DB(또는 스키마)를 공유할 수 있습니다. 이때 DB가 더 넓게 잡은 경계 컨텍스트 를 나타냅니다. 결제 처리를 신용카드/페이팔/기프트카드 등으로 쪼갰지만 동일 결제 데이터를 공유해야 하는 경우가 그 예입니다.

트레이드오프의미
변경 제어 어려움DB 스키마 변경 시 여러 서비스의 변경·배포 조율
민첩성 저하DB 변경이 더 위험해지고 덜 민첩
확장성·탄력성·내결함성 영향비즈니스 상황에 따라 부정적 영향 가능

5~6개를 넘어가면 모놀리스 DB와 동일한 문제가 부활 합니다.

클라우드 고려 사항 — 컨테이너 vs 서버리스

마이크로서비스는 ‘클라우드 네이티브(cloud native)’ 아키텍처라고 부를 정도로 클라우드와 잘 맞습니다. VM·컨테이너·DB의 온디맨드 프로비저닝과 클라우드의 서비스 기반 접근이 도메인 분리 철학과 정렬됩니다. 온프레미스 배포도 쿠버네티스나 클라우드 파운드리 같은 오케스트레이션 플랫폼으로 가능합니다.

서버리스(serverless)는 별도 아키텍처가 아니다

서버리스(AWS Lambda, Google Cloud Functions, Azure Functions)는 요청에 따라 함수가 발동(trigger)되고, 실행에 필요한 자원이 요구 기반(on-demand)으로 배정되는 클라우드 컴퓨팅 모델 입니다.

서버리스 = 마이크로서비스의 배포 모델

서버리스는 아키텍처 스타일이 아니라 마이크로서비스 아키텍처의 배포 모델 중 하나 입니다. 마이크로서비스의 정의(“한 가지 일을 정말 잘하는 단일 목적, 독립적으로 배포되는 소프트웨어 단위”)가 서버리스 함수에도 그대로 들어맞기 때문입니다.

컨테이너화된 마이크로서비스든 서버리스 함수든, 쿠버네티스 위에서는 배포 난이도가 거의 같습니다. 도메인이 함수 단위로 깔끔히 떨어지면 서버리스, 그 이상의 워크로드라면 컨테이너로 배포하는 식의 선택이 자연스럽습니다.

일반적인 위험

모래알(Grains of Sand) 안티패턴 — 너무 잘게 만든다

마이크로서비스의 가장 큰 위험은 서비스를 너무 작게 만드는 것 입니다. 마크 리처즈가 2016년 이름 붙인 모래알(Grains of Sand) 안티패턴 입니다. 해변의 모래알처럼 잘게 쪼개진 서비스가 시스템을 가득 채운 모습을 떠올리면 됩니다.

마이크로 = 크기가 아니라 하는 일

마이크로 는 서비스의 크기 가 아니라 하는 일 에 관한 것입니다. “한 가지 비즈니스 행동방식”이 단위이지, “한 가지 함수”가 단위가 아닙니다.

과도한 서비스 간 통신

세분화된 성질과 엄격한 경계 컨텍스트 때문에, 서비스가 작동하려면 상호 통신이 필수 입니다. 이 통신이 요구되는 이유는 두 가지입니다.

  • 작업흐름 처리 (코레오그래피나 AWS Step Functions 같은 오케스트레이션)
  • 다른 서비스의 데이터가 필요해서 (각 서비스와 데이터가 경계 컨텍스트 안에 갇혀 있으므로)

해결책은 서비스를 더 성긴(세분도 낮은) 마이크로서비스로 통합 하는 것입니다. 트랜잭션과 마찬가지로, 통신량이 폭증한다면 그건 세분도 신호 입니다.

데이터 공유 남용

마이크로서비스에서도 데이터 공유는 허용되며, 때로는 필요합니다. 하지만 지나치면 변경 제어·확장성·내결함성·민첩성 같은 마이크로서비스의 두드러진 장점에 악영향이 미칩니다. 아키텍트는 언제 데이터를 공유해야 하고 언제 서비스 통합으로 풀어야 하는지 를 잘 판단해야 합니다.

코드 재사용·기능성 공유 — 무공유 원칙 위반

자주 간과되는 위험입니다. 어떤 공통 기능성을 커스텀 라이브러리(JAR/DLL) 로 만들어 서비스들이 공유하면, 재사용된 코드가 여러 경계 컨텍스트에 걸쳐 퍼지면서 경계 컨텍스트의 일부가 무너집니다.

영향양상
경계 컨텍스트 누출어떤 함수나 하위 도메인의 기능성 전체 가 해당 컨텍스트 안에 포함되지 않음
변경 폭발공유 코드를 변경하면 다른 경계 컨텍스트의 서비스가 망가질 수 있음
버전 관리 부담버전 관리는 도움은 되지만, 코드 공유는 생태계를 상당히 복잡하게 만듦

거버넌스

마이크로서비스 거버넌스는 일반적인 위험들을 막는 데 초점을 맞추며, 핵심 목표는 구조적 붕괴(structural decay) 방지 입니다. 아키텍트는 무엇보다 서비스 간 정적·동적 결합의 정도를 모니터링·제어 해야 합니다.

정적 결합(static coupling) — 계약과 라이브러리

정적 결합은 서비스들이 공통 커스텀 라이브러리·서드파티 라이브러리 를 공유할 때, 그리고 서비스 간 통신에 필요한 계약 의 형태로 발생합니다. 비동기 통신 프로토콜로 동적으로 분리해도, 서비스들이 공통 계약을 따르면 정적 결합은 여전히 남아 있습니다.

정적 결합 측정·관리 도구
도구역할
SBOM(Software Bill of Materials)서비스가 어떤 라이브러리/컴포넌트에 의존하는지 명세
배포 스크립트배포 시 의존성 검증
의존성 관리 도구공유 요소의 수와 변경 추적

정적 결합이 어느 정도여야 과도한지에 대한 구체 기준은 없지만, 적을수록 좋다 는 원칙으로 최소한으로 줄여야 합니다.

동적 결합(dynamic coupling) — 호출 로그와 적합성 함수

동적 결합은 정적 결합보다 관리가 훨씬 어렵습니다. 적절한 지표를 수집하려면 약간의 창의성과 일관성이 필요합니다.

호출 로그 분석

서비스가 다른 서비스를 호출할 때마다 호출된 서비스·사용된 프로토콜 같은 상호작용 정보가 로그에 기록되도록 강제합니다. 이 정보를 적합성 함수로 분석하면 동적 결합 수준을 파악할 수 있습니다.

일관된 로깅 강제

이 접근법이 작동하려면 모든 서비스가 일관된 방식으로 로깅 해야 합니다. 한 가지 방법은 일관된 API를 제공하는 로깅용 커스텀 라이브러리(JAR/DLL)를 컴파일 시점에서 모든 서비스와 바인딩 하는 것입니다.

레지스트리 기반 동적 결합 추적

각 서비스의 첫 인스턴스가 시작될 때마다 자신의 서비스 간 호출을 JSON 같은 계약 형태로 아파치 주키퍼 같은 설정 서비스에 등록 한다면, 아키텍트는 설정 서버를 쿼리해서 마이크로서비스 생태계 전체의 모든 서비스 간 호출 맵 을 얻고 그것으로 통신량을 관리·제어할 수 있습니다.

팀 토폴로지 고려 사항

마이크로서비스는 도메인 분할 방식 이므로, 팀 역시 도메인 영역별로 정렬 했을 때 가장 잘 작동합니다. 어떤 도메인 기반 요구사항이 생겼을 때 해당 도메인에 초점을 둔 교차 기능 팀이 다른 팀이나 서비스를 방해하지 않고 그 도메인 서비스 안에서 요구된 기능을 구현할 수 있습니다.

기술적 분할 팀과 충돌

기술적으로 분할된 팀(UI팀·백엔드팀·DB팀 등)은 도메인 분할 방식의 이 아키텍처와 잘 맞지 않습니다. 기술 팀에 도메인 기반 요구사항을 배정하면 팀 간 소통과 협업이 대부분의 조직이 감당하기 어려운 수준으로 요구됩니다.

팀 유형적합도이유
스트림 정렬 팀 (기능 전담 팀)매우 높음도메인 경계가 적절히 정렬되어 있으면 가장 잘 맞음. 단, 스트림이 여러 경계 컨텍스트에 걸쳐 있으면 재조정이나 다른 아키텍처 선택 검토
활성화 팀 (역량 코칭 팀)높음전문화·횡단 관심사 공유 서비스 제공. 플랫폼 팀과 협력해 사이드카 컴포넌트 구축 가능
난해한 하위시스템 팀 (전문 도메인 팀)높음서비스 수준의 모듈성 덕분에 다른 팀과 독립적으로 난해 도메인에 집중 가능
플랫폼 팀 (공통 기반 팀)매우 높음사이드카·서비스 메시 등 횡단 운영 기능성(cross-cutting operational functionality)을 만들고 유지. 스트림 정렬 팀이 운영 문제에서 벗어남

장단점

아키텍처 특성평가
전반적인 비용매우높음($$$$$)
분할 방식도메인
퀀텀 개수1 이상
단순성★☆☆☆☆
모듈성★★★★★
유지보수성★★★★★
테스트성★★★★★
배포성★★★★★
진화성★★★★★
반응성★★☆☆☆
확장성★★★★★
탄력성★★★☆☆
내결함성★★★★★
분할 방식과 퀀텀

도메인 으로 분할되는 가장 명백한 사례입니다. 각 서비스 경계가 도메인과 일치해야 하고, 경계 컨텍스트 덕분에 현대 아키텍처 중에서 퀀텀 구분이 가장 뚜렷 합니다. 마이크로서비스는 여러 면에서 퀀텀이라는 측정 기준이 평가하려는 바를 가장 잘 보여주는 사례입니다.

내결함성 ★★★★★

서비스들이 각자 단일 목적을 지니며 다른 서비스들과 독립적이고, 세분도가 높습니다. 이러한 특징은 일반적으로 높은 내결함성 으로 이어집니다. 한 서비스의 다운이 다른 서비스로 전파되지 않습니다.

모듈성·유지보수성·테스트성·배포성·진화성·확장성 ★★★★★

마이크로서비스는 배포 자동화·지속적 테스트 같은 현대적 엔지니어링 관행을 매우 잘 지원합니다. 사실 마이크로서비스는 운영상 관심사의 자동화에 매진해 온 데브옵스 혁명 없이는 존재할 수 없었습니다.

지금까지 작성된 가장 확장성 높은 시스템 중 일부는 마이크로서비스를 활용해서 큰 성공을 거두었습니다. 운영 자동화와 지능적 통합에 의존하므로 탄력성 지원 기능을 시스템에 내장하기도 수월합니다.

진화성도 뛰어납니다. 극도로 작고 고도로 분리된 배포 단위로 구성되므로 점진적 수준(incremental level)에서 진화적 변경 을 지원합니다. 빠르게 변하는 비즈니스 속도를 따라갈 수 있습니다.

반응성 ★★☆☆☆ — 분산이 강요하는 비용

성능은 마이크로서비스에서 종종 문제가 됩니다.

성능 저하 요인양상
네트워크 호출 폭증작업 완료까지 다수의 네트워크 호출
종단점 보안 검사각 endpoint에서 신원·접근 권한 확인
데이터 지연시간(data latency)한 요청에 여러 서비스 협력 = 여러 번의 DB 호출

성능 향상 패턴이 많이 개발되어 있습니다. 지능적 데이터 캐싱·복제, 그리고 오케스트레이션보다 코레오그래피 를 선호하는 이유가 여기에 있습니다 — 결합도가 낮을수록 통신이 빨라지고 병목이 줄어듭니다.

탄력성 ★★★☆☆

확장성과 별개로 측정되는 탄력성은 중간 정도입니다. 서비스 수가 많고 의존성이 복잡할수록 한 부분의 증가가 다른 부분의 한계에 부딪힐 수 있습니다.

단순성 ★☆☆☆☆ — 비용은 가장 높다

극단적인 분리를 추구하는 기본 철학이 골칫거리가 되기도 하고, 비용도 매우 높습니다($$$$$). 운영 자동화·서비스 메시·CI/CD 파이프라인·모니터링 인프라 등 보이지 않는 비용이 많습니다.

다른 모든 아키텍처에서도 마찬가지지만, 아키텍트가 규칙을 지능적으로 깨려면 먼저 그 규칙을 이해해야 합니다.

적합한 상황

사용하면 좋은 경우

  • 기능과 데이터 모듈성이 높은 시스템 (도메인 단위로 명확히 떨어지는 비즈니스)
  • 빠른 변화 속도 와 진화적 변경이 핵심 가치인 비즈니스
  • 확장성·탄력성·내결함성 이 절대적으로 중요한 시스템
  • 데브옵스 자동화 역량클라우드 인프라 가 갖춰진 조직
  • 도메인 영역별로 정렬된 자율적 교차 기능 팀 을 갖춘 조직

사용하지 말아야 할 경우

  • 트랜잭션이 아키텍처의 지배적 특징 이 될 정도로 빈번한 시스템
  • 서비스 간 상호 통신이 폭증 하는 도메인 (도메인을 더 성기게 잡았어야 함)
  • 스타트업 초기 단계처럼 도메인 경계가 아직 안 잡힌 시스템 → 모듈형 모놀리스로 시작 후 분할
  • 데브옵스·운영 자동화 역량이 없는 조직 (운영 비용 폭발)
  • 단일 도메인의 간단한 CRUD 애플리케이션
  • 성능(반응성)이 최우선 인 저지연 시스템

예시

환자 의료 모니터링 시스템

기능과 데이터 모듈성이 높은 시스템의 좋은 사례입니다. 심박수·혈압·산소 수치·혈당·호흡수·체온 같은 활력 징후(vital sign)를 모니터링하는 의료 시스템을 마이크로서비스로 설계합니다.

flowchart TB
    HR[Heart Rate 서비스] --- DB1[(DB)]
    BP[Blood Pressure 서비스] --- DB2[(DB)]
    OL[Oxygen Level 서비스] --- DB3[(DB)]
    BS[Blood Sugar 서비스] --- DB4[(DB)]
    RR[Respiration Rate 서비스] --- DB5[(DB)]
    BT[Body Temperature 서비스] --- DB6[(DB)]
    HR & BP & OL & BS & RR & BT -.-> Display[Display Vital Signs<br/>공유 서비스]
    HR & BP & OL & BS & RR & BT -.-> Alert[Alert Staff<br/>공유 서비스]

각 활력 징후가 별도 데이터를 요구하는 독립적 기능성에 대응하므로, 경계 컨텍스트 개념에 자연스럽게 들어맞습니다. 단, 한 활력 징후 서비스가 다른 활력 징후 서비스에서 추가 정보를 가져오는 경우는 이 독립성의 예외입니다(예: 심박수 서비스가 수면 모니터 서비스에서 추가 정보 조회).

공유 서비스: 알림과 표시

알림(notification) 기능성은 모든 활력 징후 서비스에 공통이므로 Alert Staff(의료진 호출) 공유 서비스 로 표현됩니다. 측정값 이상 감지 시 간호사·의사에게 알립니다. 마찬가지로 Display Vital Signs(활력 징후 표시) 공유 서비스 가 환자실 모니터로 측정값을 비동기 전송합니다.

이 예시에서 드러나는 강점
특성어떻게 드러나는가
내결함성한 활력 징후 서비스가 다운되어도 나머지 모니터링은 정상 작동. 의료 환경에서 결정적
테스트성혈압 모니터링 서비스 일부 유지보수 시, 테스트 범위가 작아 완전 테스트 보장. 다른 서비스 영향 없음도 보장
진화성새 활력 징후 모니터(예: ECG)를 다른 서비스에 영향 없이 추가 가능

비교 / 트레이드오프

스타일공통점차이점
Ch17 오케스트레이션 주도 서비스 지향 아키텍처”서비스” 명칭 공유, 분산 아키텍처SOA: 기술 분할·공유 DB·중앙 ESB, 마이크로서비스: 도메인 분할·서비스별 DB·자율성. 거의 모든 면에서 정반대
Ch14 서비스 기반 아키텍처분산, 도메인 단위 서비스서비스 기반은 소수의 굵은 도메인 서비스 + 단일 DB 가능, 마이크로서비스는 다수의 미세 서비스 + 서비스별 DB 강제
Ch15 이벤트 주도 아키텍처비동기 통신·코레오그래피 가능EDA는 이벤트 기반 통신이 본질, 마이크로서비스는 도메인 분할이 본질. 마이크로서비스 안에서 EDA 통신 스타일 채택 가능
Ch16 공간 기반 아키텍처분산, 클라우드 친화공간 기반은 캐시 기반 극단적 확장성에 초점, 마이크로서비스는 도메인 분리에 초점
Ch11 모듈형 모놀리스 아키텍처도메인 분할모듈형 모놀리스는 단일 배포·DB. 마이크로서비스 도입 전 도메인 경계를 시험하는 단계 로 적합
마이크로서비스가 SOA에 진 빚
SOA의 교훈마이크로서비스의 답
기술 분할은 변경 비용을 폭발시킴도메인 분할 로 전환
단일·소수 DB 공유는 결합 폭탄서비스별 DB 강제
중앙 오케스트레이션은 병목·관료화코레오그래피 우선 + 필요 시 지역 중재자
전체론적 재사용은 결합으로 변함적당한 중복 허용, 무공유
정교한 분류 체계는 변경을 막음자율적 도메인 팀, 팀 토폴로지 정렬

내 생각

  • 이 챕터의 가장 큰 가치는 “마이크로서비스 = 작은 서비스”라는 통념을 정면으로 부정 한다는 점입니다. 마틴 파울러의 “이름표(label)이지 설명(description)이 아니다”라는 인용이 인상 깊습니다. “분산된 진흙잡탕(Big Ball of Distributed Mud)“의 대부분은 세분도 결정 단계의 실패 에서 온다고 생각합니다.

  • 서비스당 데이터베이스(Database-per-Service) 가 이 챕터의 가장 강력한 실천 원칙입니다. SOA가 망한 이유와 마이크로서비스가 제대로 된 분리를 만드는 이유가 모두 데이터 토폴로지로 환원됩니다. “DB를 공유하는 순간 경계 컨텍스트는 사라진다” 는 문장은 도메인 모델링 결정의 1차 가드레일로 항상 머릿속에 둘 만합니다. “마이크로서비스는 했는데 DB는 통합 DB에서 안 뺐어요”는 이 원칙 위반의 전형입니다.

  • 모래알(Grains of Sand) 안티패턴”과 “과도한 서비스 간 통신”은 같은 문제의 두 얼굴입니다. 둘 다 해결책이 똑같습니다. 세분도를 다시 잡아라. 이는 마이크로서비스가 결국 세분도 거버넌스 게임 임을 시사합니다. 적합성 함수로 호출 그래프를 모니터링하고, 임계치를 넘으면 서비스를 합치는 운영 루틴이 마이크로서비스 거버넌스의 본질입니다.

  • 의료 모니터링 시스템 예시는 마이크로서비스가 빛나는 도메인 형태 를 압축적으로 보여줍니다. “서로 거의 독립적인 다수의 단순 도메인 + 명확한 횡단 관심사 한두 개(알림·표시)” 라는 패턴입니다. 핀테크의 결제 수단별 처리, 이커머스의 카탈로그 종류별 검색, IoT 센서 수집 등이 같은 형태입니다. 반대로 ERP나 CRM처럼 도메인 사이 트랜잭션이 본질 인 시스템은 마이크로서비스가 적합하지 않다는 점이 자연스럽게 도출됩니다.

더 알아볼 것

  • Software Architecture: The Hard Parts 7장 (서비스 세분도) 정리
  • Software Architecture: The Hard Parts 12장 (8가지 사가 패턴) 정리
  • Sam Newman, Building Microservices 2판 — 데이터 분해와 통신 패턴
  • Luca Mezzalira, Building Micro-Frontends 2판 — UI까지 경계 컨텍스트로 가져가는 방법
  • 마이크로서비스 거버넌스용 적합성 함수 패턴 (호출 그래프·정적 결합 임계치)
  • Apache Zookeeper / etcd / Consul 기반 동적 결합 추적 실전 패턴
  • Istio·Linkerd 서비스 메시의 운영 차이와 도입 비용
  • AWS Step Functions vs 코레오그래피 — 언제 오케스트레이션이 정당화되는가
  • 모듈형 모놀리스에서 마이크로서비스로 분할하는 실전 단계 (Strangler Fig 패턴)
  • 분산 모놀리스(distributed monolith) 진단 체크리스트

관련 개념

출처

  • 마크 리처즈, 닐 포드, 『소프트웨어 아키텍처 The Basics』, 18장 마이크로서비스 아키텍처
  • 마틴 파울러·제임스 루이스, “Microservices” 블로그(2014)
  • Sam Newman, Building Microservices, 2판 (O’Reilly, 2021)
  • Luca Mezzalira, Building Micro-Frontends, 2판 (O’Reilly, 2025)
  • Mark Richards, Microservices vs. Service-Oriented Architecture (O’Reilly, 2016)
  • Mark Richards, Microservices AntiPatterns and Pitfalls (O’Reilly, 2016)
  • 닐 포드 외, Software Architecture: The Hard Parts (O’Reilly, 2021) — 7장(세분도), 12장(사가 패턴)