Loading...
Skip to Content

왜 마이크로서비스 아키텍처는 어려운가?

"마이크로서비스로 전환했는데, 시스템은 더 느려지고 장애는 더 잦아졌으며 배포는 오히려 더 무서워졌다." — MSA 전환 프로젝트를 경험한 조직에서 어렵지 않게 들을 수 있는 고백입니다. 마이크로서비스 아키텍처는 독립적인 배포, 탄력적인 확장, 장애 격리라는 매력적인 약속을 내걸지만, 그 약속이 현실이 되는 조직은 생각보다 많지 않습니다.

왜일까요? 결론부터 말하면, 마이크로서비스의 어려움은 '기술'이 아니라 '설계'에서 온다는 것이 우리의 경험입니다. Kubernetes를 도입하고 서비스를 여러 개로 쪼개는 일은 이제 어렵지 않습니다. 정작 어려운 것은 "어디에 경계선을 긋는가", "데이터는 누가 소유하는가", "트랜잭션 없이 어떻게 일관성을 지키는가"라는 세 가지 설계 질문입니다. 이 글에서는 유엔진이 다년간의 MSA 컨설팅과 교육에서 반복적으로 목격해 온 세 가지 함정을 짚고, 그 해답이 되는 설계 원칙들을 관련 심화 글과 함께 안내합니다. 아울러 그 해답을 채택한 뒤에도 설계·구현·운영·배포로 이어지는 프로젝트 라이프사이클 전 단계에서 만나게 되는 난제들의 지도까지 함께 그려봅니다.

  1. 약속과 배신: 왜 쪼갰는데 더 복잡해졌는가

모놀리스가 한계에 부딪히는 이유는 명확합니다. 내부 모듈 간의 강한 결합(Tight Coupling) 때문에 작은 변경이 전체로 전파되고, 일부 기능의 부하가 시스템 전체의 증설을 강요하며, 한 곳의 장애가 서비스 전면 중단으로 이어집니다. 그래서 우리는 시스템을 쪼갭니다.

그런데 여기서 첫 번째 오해가 시작됩니다. "쪼개면 마이크로서비스가 된다"는 오해입니다. 잘못 쪼갠 시스템은 모놀리스의 결합도를 그대로 간직한 채 네트워크 비용만 추가된 분산 모놀리스(Distributed Monolith)가 됩니다. 프로세스 내부의 함수 호출이었던 것이 네트워크를 타는 원격 호출로 바뀌었을 뿐, 여전히 모든 서비스가 서로를 붙잡고 있는 상태죠. 이때 시스템은 모놀리스의 단점(강결합)과 분산 시스템의 단점(지연, 부분 장애, 운영 복잡도)을 동시에 갖게 됩니다.

좋은 분해와 나쁜 분해를 가르는 기준은 소프트웨어 공학의 오래된 두 개념, 응집도(Cohesion)와 결합도(Coupling)입니다. 한 서비스 안의 요소들이 하나의 명확한 목적을 위해 뭉쳐 있으면 응집도가 높은 것이고, 서비스들끼리 서로의 데이터와 기능에 의존하는 정도가 낮으면 결합도가 낮은 것입니다. 높은 응집도, 낮은 결합도 — 마이크로서비스 설계의 모든 원칙은 결국 이 한 문장으로 수렴합니다.

  2. 함정 ① 데이터 관점의 분해 — 수다쟁이 마이크로서비스

MSA 전환에서 가장 흔한 실수는 서비스를 데이터베이스(테이블) 관점으로 쪼개는 것입니다. 고객 테이블이 있으니 '고객 서비스', 주문 테이블이 있으니 '주문 서비스', 배달 정보가 있으니 '배달 서비스'… 언뜻 자연스러워 보이지만, 이렇게 나누면 하나의 업무 흐름을 처리할 때마다 여러 서비스에 흩어진 데이터를 동기 호출(Req/Res)로 일일이 긁어와야 합니다.

이것이 대표적인 안티패턴인 수다쟁이 마이크로서비스(Chatty Microservice)입니다. 식당에 비유하면, 빵·채소·고기 같은 재료를 종류별 창고에 모아두고 주문이 들어올 때마다 창고를 순회하며 재료를 가져오는 주방과 같습니다. 공장과 창고의 비유로 말하면, 조립 공장이 부품 공장의 원자재 창고에 수시로 직접 드나드는 구조입니다. 서비스 간 통신이 폭증하고, 어느 한 서비스라도 응답이 늦어지면 전체 흐름이 함께 느려지며, 한 곳의 장애가 도미노처럼 전파됩니다.

❌ 데이터 중심 분해
🗄️ 고객 서비스 🗄️ 주문 서비스 🗄️ 배달 서비스
요청마다 동기 호출(Req/Res)이 얽히는
Chatty Microservice · 강결합 · 장애 전파
✅ 행위(비즈니스 프로세스) 중심 분해
🛒 주문하기 🍳 조리하기 🛵 배달하기
각 컨텍스트가 필요한 데이터를 스스로 보유,
결과는 도메인 이벤트 Pub/Sub로 전달 · 독립 운영

같은 배달 애플리케이션도 어디에 경계선을 긋느냐에 따라 전혀 다른 아키텍처가 된다

해법은 경계선을 데이터가 아니라 행위(비즈니스 프로세스의 단계, 밸류 스트림)를 기준으로 긋는 것입니다. '주문한다 → 조리한다 → 배달한다'라는 흐름의 각 단계(관심사)마다 그 행위에 필요한 데이터와 기능을 함께 묶어 바운디드 컨텍스트(Bounded Context)를 정의하면, 각 서비스는 자기 일에 필요한 것을 자기 안에 갖게 되고(높은 응집도), 다른 서비스에는 행위의 결과인 도메인 이벤트만 비동기(Pub/Sub)로 전달하면 됩니다(낮은 결합도). 한쪽에 장애가 나도 다른 서비스는 계속 동작하는, 마이크로서비스의 이상적인 모습이 이때 비로소 나타납니다.

  3. 함정 ② 모두의 데이터 — 갓테이블의 유혹

경계선을 그었다면 다음 질문이 기다립니다. "그래서 이 데이터는 누구의 것인가?" 모놀리식 시스템에는 어김없이 영업·마케팅·예약 등 온갖 도메인의 컬럼이 한데 뒤엉킨 거대한 테이블이 존재합니다. 이른바 갓테이블(God Table)입니다. 모든 도메인이 이 테이블 하나에 의존하기 때문에, 한 도메인의 변경이 전 도메인으로 번지고 중앙 데이터베이스는 병목이 됩니다. 갓테이블을 그대로 둔 채 애플리케이션만 쪼개면, 모든 서비스가 하나의 DB를 붙드는 공유 데이터베이스 안티패턴이 되어 MSA의 의미가 사라집니다.

데이터 분리의 3원칙

  • 📍 데이터 지역성(Data Locality): 각 바운디드 컨텍스트는 자기 문제 영역에서 자주 읽고 쓰는 데이터만 로컬로 소유합니다. 다른 도메인의 엔티티는 통째로 끌어안지 말고 ID Value Object로만 참조합니다.
  • 📋 공통 데이터 복제(Common Data Duplication): 이름·성별처럼 거의 변하지 않는 데이터는 이벤트를 통해 각 서비스에 복제해 둡니다. "중복은 무조건 악"이라는 모놀리스 시대의 정규화 본능을 내려놓는 것이 핵심입니다. 복제는 동기화 비용보다 훨씬 싼 자율성의 대가입니다.
  • 📞 원격 호출은 최후의 수단(Remote Invocation — Last Resort): 자주 변해서 복제가 곤란한 데이터만 호출 시점에 가져오되, 캐시와 플라이웨이트 패턴으로 호출 비용과 장애 취약성을 줄입니다.

이 세 원칙의 우선순위가 중요합니다. 지역화 먼저, 그다음 복제, 원격 호출은 마지막. 많은 프로젝트가 이 순서를 거꾸로 적용해서(모든 것을 원격 호출로 해결) 함정 ①의 수다쟁이 마이크로서비스로 되돌아갑니다.

  4. 함정 ③ 사라진 트랜잭션 — 일관성과 성능의 줄다리기

모놀리스에서는 당연했던 것이 MSA에서는 사라집니다. 바로 하나의 트랜잭션으로 모든 것을 묶는 능력입니다. 주문 저장과 재고 차감을 한 트랜잭션에서 커밋하던 시절은 끝났습니다. 데이터가 서비스별로 분산된 순간, "전부 성공 아니면 전부 롤백"이라는 안전망은 더 이상 공짜가 아닙니다. 이것이 많은 아키텍트가 MSA 앞에서 느끼는 가장 근본적인 공포입니다.

해답은 일관성의 범위를 재정의하는 데 있습니다. 도메인 주도 설계(DDD)의 어그리게이트(Aggregate)는 "반드시 즉시, 함께 일관되어야 하는 객체들의 묶음"으로, 강한 일관성이 필요한 최소 경계를 정의합니다. 어그리게이트 안쪽은 원자적으로 업데이트하여 불변식을 지키고, 어그리게이트 사이·서비스 사이는 이벤추얼 컨시스턴시(Eventual Consistency) — "지금 당장은 아니어도 결과적으로는 일관된다" — 로 관리합니다. 주문 서비스가 주문을 저장하며 이벤트를 발행하면, 재고 서비스가 이를 구독해 자기 페이스로 재고를 갱신하는 식입니다.

물론 공짜는 아닙니다. 이 스타일을 채택하는 순간 따라오는 숙제들이 있습니다.

  • 🔁 멱등성(Idempotency): 같은 이벤트가 두 번 도착해도 부작용이 없도록 핸들러를 설계해야 합니다.
  • ↩️ 보상 트랜잭션과 Saga: 중간 단계가 실패했을 때 이미 완료된 앞 단계를 되돌리는 시나리오를 Saga 패턴으로 명시적으로 설계해야 합니다.
  • ⏱️ 일관성 윈도우: "얼마나 오래 불일치를 허용할 수 있는가"를 비즈니스와 합의하고 모니터링해야 합니다.
  • 📏 어그리게이트 크기: 너무 크면 모놀리스 시절의 잠금 경합이 재현되고, 너무 작으면 조율 비용이 폭증합니다. 경계 설정 자체가 설계 역량입니다.

  5. 해답: 세 가지 함정을 넘는 설계 원칙

정리하면, 마이크로서비스가 어려운 이유는 세 가지 함정 — 잘못된 경계, 소유자 없는 데이터, 사라진 트랜잭션 — 이 서로 맞물려 있기 때문입니다. 그리고 각 함정에는 검증된 처방이 있습니다.

함정 증상 처방 원칙 깊이 읽기
① 데이터 관점의 분해 서비스 간 동기 호출 폭증, 한 서비스 지연이 전체 지연으로, 장애 도미노 행위(밸류 스트림) 중심의 바운디드 컨텍스트 + 도메인 이벤트 Pub/Sub 응집도와 결합도 · 설계원칙
② 갓테이블 모든 서비스가 한 DB를 공유, 스키마 변경 공포, 중앙 DB 병목 데이터 지역성 → 공통 데이터 복제 → 원격 호출(최후의 수단) 데이터 관리 3원칙
③ 사라진 트랜잭션 분산 트랜잭션 시도, 2PC의 늪, 정합성 버그와 성능 저하의 악순환 어그리게이트 = 강한 일관성 경계, 그 밖은 이벤추얼 컨시스턴시 + Saga·멱등성 일관성과 성능 · 어그리게이트

눈치채셨겠지만 세 처방은 하나의 문장으로 이어집니다. "비즈니스 행위를 중심으로 경계를 긋고, 그 경계 안에 데이터를 지역화하며, 경계 사이는 이벤트로 느슨하게 연결하라." 마이크로서비스 설계가 어려운 진짜 이유는, 이 문장이 기술 문제가 아니라 도메인을 얼마나 깊이 이해하는가의 문제이기 때문입니다. 도메인 모델링이 낯설다면 아기돼지 3형제 이야기로 도메인 모델 이해하기비즈니스 로직을 SQL이 아닌 도메인 클래스로 관리해야 하는 이유부터 읽어보시길 권합니다.

  6. 해답의 청구서 — 라이프사이클 전 단계에서 만나는 난제들

여기까지 읽고 "행위 중심으로 경계를 긋고 이벤트로 연결하면 되는구나"라고 정리했다면, 절반만 맞습니다. 이벤트 기반 마이크로서비스 아키텍처(EDMSA)는 확장성, 결합도 분리, 실시간 처리에서 뛰어난 해답이지만, 이 처방을 받아들이는 순간 어려움이 사라지는 것이 아니라 형태를 바꿔 프로젝트 라이프사이클 전 단계로 흩어집니다. "분산 환경의 복잡성"과 "비동기 메시징"이 결합되면서 설계·구현·운영·배포 각 단계마다 고유한 난제가 기다립니다. 미리 지도를 그려두면 겁낼 일이 아니라 체크리스트가 됩니다.

📐 1. 설계 단계
  • 이벤트의 굵기: 과도하게 세분화하면 메시지 폭증, 너무 크게 묶으면 결합도 상승 — 적정선 찾기가 곧 설계
  • 이벤트 스키마 버전 관리: 하위 호환을 지키며 진화시키는 거버넌스(Schema Registry, Avro/Protobuf)가 없으면 수신 서비스가 깨짐
  • 2PC의 불가: 단일 ACID 트랜잭션 없이 최종 일관성의 시간차를 UX와 비즈니스 로직에 반영해야 함 ("주문 완료" 후 정산 반영 지연)
  • Saga 설계 복잡성: 실패 시 보상 트랜잭션을 일일이 설계하고, 오케스트레이션 vs 코레오그래피 방식도 선택해야 함
🛠️ 2. 구현 단계
  • Dual Write 문제: DB 저장은 성공했는데 브로커 발행이 실패하는 원자성 균열 — Transactional Outbox나 CDC(Debezium)로 풀어야 하며 그만큼 인프라·개발 공수 추가
  • 멱등성: At-Least-Once 전달 특성상 중복 수신은 기본값 — 모든 컨슈머가 중복 실행에 안전해야 함
  • 순서 역전: 지연·재시도로 '주문 생성 → 취소'가 뒤바뀔 수 있어 파티셔닝 키 전략 필수
  • Poison Pill: 계속 실패하는 메시지가 큐를 막지 않도록 DLQ 격리 + 백오프 재시도 + 재처리(Replay) 메커니즘 구축
📡 3. 운영·관찰 가능성
  • 끊긴 호출 스택: 비동기 이벤트는 콜스택이 끊겨, Correlation/Trace ID를 이벤트 헤더로 전파하고 OpenTelemetry·Zipkin·Jaeger와 연동하지 않으면 "어디서 멈췄는지"를 알 수 없음
  • 브로커 자체가 거대한 인프라: Kafka·RabbitMQ의 HA, 파티션 관리, 보존 기간, 백프레셔, 컨슈머 랙 적체 대응
  • 이벤트 재처리: 버그 수정 후 과거 이벤트를 Replay할 때 부작용(이메일 재발송 등) 없이 데이터만 재동기화하는 절차의 복잡성
🚢 4. 배포·진화 단계
  • 신·구 버전 동시 기동: 카나리/블루-그린 배포 순간 "어느 버전이 이 이벤트를 소비하는가" — 스키마 변경이 겹치면 구 컨슈머가 신 이벤트를 읽고 깨질 수 있어 비파괴적 변경(Non-breaking change) 전략과 정교한 배포 순서 필요
  • 파티션 구조 변경: 트래픽 증가로 파티션을 늘리는 순간 순서 보장 키 매핑이 깨져 이벤트 순서가 꼬일 수 있음

이벤트 기반 MSA 프로젝트가 라이프사이클 단계별로 마주하는 난제 지도

"비동기 이벤트 기반 아키텍처는 결합도를 낮춰주는 대신, 시스템 전체의 상태를 파악하고 제어하는 난이도를 대폭 상승시킨다." — 그래서 EDMSA 도입 전에는 최소한 네 가지를 사전 검토해야 합니다.

  • 📤 ① Transactional Outbox 패턴·CDC의 표준 적용 여부
  • 🔭 ② OpenTelemetry 기반 End-to-End 분산 트레이싱 체계
  • 📜 ③ Schema Registry를 통한 이벤트 스키마 거버넌스
  • 🧰 ④ 컨슈머 멱등성 처리와 DLQ 자동화 로직의 공통 라이브러리화

이 목록은 겁을 주기 위한 것이 아닙니다. 하나하나가 이미 검증된 표준 패턴과 도구가 존재하는, 정복 가능한 난제라는 점이 핵심입니다. 읽기 모델 분리로 조회 복잡도를 다루는 CQRS도 그 무기고의 하나입니다. 그리고 이 난제들이 실제 대규모 프로젝트에서 어떻게 하나씩 처리되는지는, 바로 다음의 정부24 사례 — Saga·멱등성·재시도·DLQ가 그대로 등장합니다 — 가 보여줍니다.

  7. 원칙은 현장에서 통하는가 — 정부24 클라우드 네이티브 전환 사례

이 원칙들이 교과서 속 이야기가 아니라는 것을 보여주는 사례가 정부24 포털의 클라우드 네이티브 전환입니다. 유엔진솔루션즈가 설계·분석을 수행한 이 프로젝트에서, 기존 정부24는 전형적인 모놀리식 강결합 구조였고 특히 모든 민원 신청이 '민원안내' 모듈을 거쳐야만 하는 단일 장애점(SPOF)을 안고 있었습니다. 이 모듈 하나가 멈추면 대한민국의 모든 온라인 민원이 함께 멈추는 구조였죠.

전환 설계의 핵심은 앞서 본 원칙 그대로였습니다. 민원이라는 도메인을 업무 행위의 성격에 따라 세 유형으로 나누고, 유형마다 다른 패턴을 적용했습니다.

  • ⚡ 단순신청·즉시발급 민원: 응답 속도가 생명이므로 동기식 REST 호출을 유지하되, 다른 서비스의 DB를 직접 갱신하던 강결합을 명확한 API 인터페이스로 대체 — 모든 것을 이벤트로 만들지 않는 것도 설계입니다.
  • 📨 유기한·비연계 민원: 즉시 접수 응답 후 백그라운드에서 이벤트스토어 기반 Pub/Sub으로 처리. Saga 패턴으로 프로세스 일관성을, 멱등성과 재시도·DLQ로 메시지 처리의 신뢰성을 확보 — 함정 ③의 처방이 그대로 적용된 지점입니다.
  • 🏛️ 주요 민원(건축물대장, 자동차등록 등): 트래픽과 대민 영향도가 큰 서비스는 독립 네임스페이스로 격리 배포하고 전용 안내 채널을 두어, SPOF 문제를 구조적으로 해소.

목표 수치는 시스템 용량 최대 7.6배 자동 확장, 서비스 중단 시간 81.6% 감소, 처리 속도 36.7% 단축. "왜 어려운가"를 정면으로 통과한 설계가 어떤 결과 목표를 감당할 수 있는지 보여주는 사례입니다. 상세한 AS-IS/TO-BE 아키텍처 분석은 정부24 전환기 전문에서 확인할 수 있습니다.

  8. 혼자 넘기 어려운 산이라면 — 설계 원칙에서 제품·서비스까지

마이크로서비스 아키텍처는 어렵습니다. 그러나 그 어려움의 정체는 분명합니다. 경계 설정, 데이터 소유권, 일관성 전략 — 세 가지 설계 판단이며, 모두 학습과 경험으로 넘을 수 있는 산입니다. 그리고 유엔진은 이 산을 넘는 여정 전체 — 진단 → 설계 → 구현 → 현대화 → 역량 내재화 — 를 제품과 서비스로 촘촘하게 이어두었습니다. 이 글에서 다룬 개념 하나하나가 어느 제품의 어떤 기능으로 실행되는지 그대로 따라가 보세요.

세 가지 함정을 넘는 설계 판단이 유엔진의 제품·서비스 라인업으로 그대로 이어진다

이 글의 개념 이를 실행하는 제품·서비스 기능
경계선을 긋기 전, 현재 시스템의 실제 응집 구조 파악 (함정 ① 예방) Robo Legacy Analyzer — 소스코드·DDL을 그래프로 분석하고, 자주 협력하는 함수를 자동 군집화해 숨어 있던 바운디드 컨텍스트 후보를 드러냅니다.
↗ 소개 페이지에서 보기
행위 중심의 바운디드 컨텍스트·어그리게이트 설계 (함정 ①·③ 처방) Robo Architect — Aggregate·이벤트스토밍 설계를 AI와 함께 수행하고 도메인 이벤트 흐름을 시각적으로 다듬습니다.
↗ 소개 페이지에서 보기
설계를 이벤트 기반 마이크로서비스 코드로 — 멱등성·Saga까지 손으로 짜는 부담 줄이기 Robo Architect — DDD 기반 코드·테스트 자동 생성으로 설계 모델이 곧바로 실행 가능한 서비스가 됩니다.
↗ 소개 페이지에서 보기
레거시 분석 결과를 그대로 전환 설계의 입력으로 Robo Legacy Analyzer × Robo Architect 연동 — 그래프 분석이 그대로 전환 설계가 됩니다.
↗ 소개 페이지에서 보기
갓테이블과 SQL에 갇힌 비즈니스 로직을 도메인 클래스로 해방 (함정 ② 해체, Part1·Part2의 주제) Robo Modernizer — 스토어드 프로시저를 분석해 Java 도메인 코드로 자동 전환합니다.
↗ 소개 페이지에서 보기
정부24처럼 검증된 첫걸음 — 원칙이 통하는지 작게 먼저 증명 선도개발 구현 서비스 — 핵심 구간을 빠르게 프로토타이핑해 아키텍처 결정을 실물로 검증합니다.
↗ 서비스 소개 보기
경계 설계 역량을 조직에 내재화 — 도구는 사더라도 판단력은 길러야 CNA/MSA 컨설팅·교육 — 진단부터 운영 안정화까지의 컨설팅 프로세스와 CNMM 성숙도 모형 기반 교육 과정.
↗ 컨설팅 서비스 보기 · ↗ 교육 프로그램 보기

어디서부터 시작할지 막막하다면, 다음 두 갈래 중 하나로 들어오시면 됩니다.

  • 🧭 CNA/MSA 컨설팅: 정부24를 비롯한 대규모 전환 프로젝트의 경험을 바탕으로, 이벤트스토밍 기반의 경계 설계부터 전자정부 표준 프레임워크 기반의 구현·운영까지 전 과정을 지원합니다. → CNA/MSA Consulting · MSA Case Studies · 선도개발 구현 컨설팅
  • 🎓 MSA School: 이 글에서 다룬 응집도·결합도, 갓테이블 분해, 어그리게이트와 이벤추얼 컨시스턴시를 실습으로 체득하는 마이크로서비스 전문 교육 사이트입니다. 8,000명 이상의 수료생이 거쳐 간 커리큘럼을 만나보세요. → MSA School 바로가기