Software Architecture/Architectural Styles
Architectural Styles - 05. 마이크로서비스
마이크로서비스 — 분해와 독립성의 약속
2014년 3월, James Lewis와 Martin Fowler는 martinfowler.com에 "Microservices"라는 글을 올렸다. 당시 이미 여러 기업(Netflix, Amazon)이 이런 식의 아키텍처로 시스템을 운영하고 있었지만, '마이크로서비스'라는 이름과 특성을 처음 정리한 것은 이 글이었다. 그 후 10년 동안 마이크로서비스는 업계를 휩쓸었다 — 그리고 많은 곳에서 실패했다. Sam Newman이 2판(2021)에서 가장 강조하는 메시지는 1판(2015)과 미묘하게 다르다 — 분해보다 '독립성'과 '비용'을 더 직시한다. 이 글이 다루는 질문: 마이크로서비스를 정의하는 것은 '작음'인가, '독립성'인가. 답부터 말하면 — '작음'은 부수물이고, 본질은 '독립 배포 가능(independently deployable)'이라는 속성에 있다.
비유로 감 잡기 — 다세대주택과 원룸
10가구가 사는 10층짜리 건물을 상상하자. 각 층은 한 가구가 산다. 1층 가구의 수도가 망가지면 1층만 물이 안 나온다 (장애 격리). 2층 가구가 인테리어를 할 때 다른 가구의 허락이 필요 없다 (독립 배포). 3층 가구가 전기를 많이 쓰면 3층 전기 계량기만 빨리 돈다 (독립 확장). 각 가구는 자기 수도, 자기 전기, 자기 가스 계량기를 갖는다 (서비스별 데이터 저장소).
모놀리스는 한 채의 단독주택에 10가구가 함께 사는 형태다. 한 가구가 부엌 수도를 고치면 모든 가구가 물이 안 나온다. 다 같이 살기 때문에 단순하고 효율적이지만, 한 가구의 문제가 모두에게 전파된다.
마이크로서비스가 추구하는 것은 다세대주택 모델이다 — 각 서비스(가구)가 자기 상태(DB)를 갖고, 자기 인프라를 갖고, 자기 배포 주기를 갖는다. 이 독립성이 주는 효용이 마이크로서비스의 본질이다. '크기'는 부수물이다 — 다세대주택의 한 호실이 10평이든 30평이든 '독립된 호실'이라는 속성이 핵심이지, 평수가 핵심이 아니다.
비유의 한계 — 건물 비유는 '물리적 독립'을 강조하지만, 마이크로서비스의 독립은 논리적·운영적이다. 프로세스는 분리되지만, 여전히 같은 데이터센터나 같은 쿠버네티스 클러스터에 있을 수 있다. 또한 다세대주택은 가구 간 소통이 적지만, 마이크로서비스는 빈번히 통신한다. 비유는 '통신 비용'에서 무너진다.
마이크로서비스를 정의하는 여섯 속성
Fowler와 Lewis가 2014년 글에서 정리한 특성, 그리고 Newman이 2판에서 강화한 정의를 종합하면, 마이크로서비스를 규정하는 속성은 대략 여섯 가지다.
- 서비스별 데이터 저장소 — 각 서비스가 자기 DB(또는 최소한 자기 스키마)를 갖는다. 다른 서비스의 DB에 직접 접근하지 않는다.
- 독립 배포 가능 — 한 서비스의 변경이 다른 서비스의 재배포를 요구하지 않는다.
- 비즈니스 능력 기반 분해 — 기능(주문, 결제, 배송)이 아니라 비즈니스 능력 단위로 서비스를 자른다.
- 탈중앙화 — 중앙协调자(coordinator)를 최소화하고, 서비스 간 느슨한 결합을 지향한다.
- 다양한 기술 허용(polyglot) — 서비스마다 적합한 언어·저장소를 선택할 수 있다.
- 관측성(observability) 내재화 — 분산 환경에서 추적·로그·메트릭이 필수이므로, 처음부터 고려한다.
이 여섯 속성 중 Newman이 2판에서 가장 강조하는 건 '독립 배포 가능'이다. "독립 배포가 안 되면, 아무리 작아도 마이크로서비스가 아니다"가 그의 단호한 입장이다.
flowchart TD
subgraph MS["마이크로서비스 아키텍처"]
OS["Order Service<br/>+ orders DB"]
PS["Payment Service<br/>+ payments DB"]
IS["Inventory Service<br/>+ inventory DB"]
SS["Shipping Service<br/>+ shipping DB"]
end
OS <-. API/이벤트 .-> PS
OS <-. API/이벤트 .-> IS
OS <-. API/이벤트 .-> SS
OS x--x|"DB 직접 접근 금지"| PS
분해 기준 — 비즈니스 능력과 하위 도메인
마이크로서비스 설계의 핵심 질문은 "어떻게 자를 것인가"다. 두 가지 주된 기준이 있다.
- 비즈니스 능력(business capability) — 조직이 수행하는 비즈니스의 기능적 분해. "주문 받기", "결제 처리", "재고 관리", "배송" 같은 능력 단위. Conway의 법칙에 따르면 이는 보통 조직의 팀 구조와 일치한다.
- 하위 도메인(subdomain) — DDD(Evans 2003) 관점에서 문제 공간의 하위 영역. "주문 도메인 안에서 핵심(core)인지 지원(generic)인지"에 따라 자른다.
Newman은 2판에서 이 두 기준을 보완적으로 본다 — 비즈니스 능력으로 시작해 도메인 경계로 정제하라고. 처음엔 조직 구조에서 힌트를 얻고(어느 팀이 무엇을 담당하나), 이후 도메인 전문가와 대화하며 경계를 다듬는다. 이 과정이 DDD의 '전략적 설계'(바운디드 컨텍스트 식별)와 정확히 겹친다.
분해 기준 판단표
| 자르는 기준 | 예시 | 장점 | 단점 |
|---|---|---|---|
| 비즈니스 능력 | 주문/결제/재고/배송 | Conway와 정렬, 직관적 | 도메인 깊이가 얕을 수 있음 |
| 하위 도메인 (DDD) | 주문 컨텍스트 내 핵심/지원 구분 | 도메인 응집 높음 | 도메인 전문가 필요 |
| 기술적 계층 (안티) | 모든 Service 클래스, 모든 Repository | (없음) | 서비스가 너무 커플링 — 분산 모놀리스 |
| CRUD 엔터티 (안티) | OrderService, CustomerService, ItemService | 직관적 | 비즈니스 흐름 단위가 아님 — 빈약한 서비스 |
마지막 두 기준은 흔한 실수다. 기술 계층이나 CRUD 엔터티로 자르면, 한 비즈니스 흐름(예: '주문')이 여러 서비스를 건드리게 되고, 그것이 분산 모놀리스의 원인이 된다. 자르는 단위는 비즈니스 흐름이어야 한다.
서비스별 데이터 저장소 — 가장 결정적인 속성
마이크로서비스를 다른 분산 아키텍처와 구분하는 가장 결정적인 속성이 이것이다. Newman이 2판에서 집중적으로 강조하는 부분이기도 하다.
"서비스별 DB"는 단순히 "각 서비스가 자기 테이블을 갖는다"가 아니다. 각 서비스가 다른 서비스의 DB에 직접 접근하지 못해야 한다. 한 서비스의 데이터가 필요하면, 그 서비스의 API를 호출해야 한다.
// 안티패턴 — Order Service가 Payment DB에 직접 접근
class OrderService {
void placeOrder(Order order) {
orders.save(order);
// 다른 서비스의 DB에 직결 (JDBC)
jdbc.query("SELECT balance FROM payments WHERE order_id = ?", order.id());
}
}
이 패턴은 "서비스를 분리하되 DB는 공유"하는 전형적 안티패턴이다. 외견상 서비스가 분리돼 있지만, 스키마가 결합돼 있어 한 서비스의 스키마 변경이 다른 서비스를 깨뜨린다. Newman이 '분산 모놀리스'라고 부르는 사례의 가장 흔은 형태다.
// 마이크로서비스 패턴 — Order Service가 Payment Service의 API 호출
class OrderService {
private final PaymentClient paymentClient; // HTTP/gRPC 클라이언트
void placeOrder(Order order) {
orders.save(order);
PaymentResponse resp = paymentClient.charge(order); // API 호출
if (!resp.success()) throw new PaymentFailedException();
}
}
데이터를 서비스 경계 밖으로 꺼내려면 API를 통해서만. 이 제약이 결합을 낮추는 핵심 메커니즘이다.
서비스별 데이터 저장소 — 구현 형태
| 패턴 | 설명 | 적합 |
|---|---|---|
| Database per service | 서비스마다 별도 DB 인스턴스 | 강력한 격리 필요 시 |
| Schema per service | 같은 DB 인스턴스, 다른 스키마 | 운영 단순화 필요 시 (중간 단계) |
| Table ownership | 같은 스키마, 서비스별 소유 테이블 | 전환 과도기 |
| Shared database (안티) | 모든 서비스가 같은 테이블에 접근 | 분산 모놀리스 — 피해야 |
이 표에서 아래로 갈수록 결합이 강해지고 마이크로서비스의 이점은 약해진다. 'Shared database'는 Newman이 가장 경계하는 패턴이다.
마이크로서비스의 이점과 비용
| 품질 속성 | 이점 | 비용 |
|---|---|---|
| 확장성 | 서비스별 독립 확장 | 전체 시스템 복잡도 증가 |
| 장애 격리 | 한 서비스 장애가 전체에 전파 제한 (동기 체인 아니면) | 분산 장애 시나리오 대비 필요 |
| 배포 민첩성 | 서비스별 독립 배포 | 배포 파이프라인 N배 |
| 기술 다양성 | 서비스마다 적합한 스택 | 운영·관측 인프라 복잡 |
| 팀 자율성 | 팀별 독립 작업 | 조직 Conway 정렬 필수 |
| 데이터 일관성 | (약화) — 최종 일관성 감수 | 분산 트랜잭션(Saga·outbox) 부담 |
| 관측성 | (복잡) — 분산 추적 필수 | 분산 추적 인프라(Jaeger·Zipkin) |
| 개발 단순함 | (약화) — 초기 진입 복잡 | 단순 모놀리스가 더 빠른 시작 |
마이크로서비스는 '무조건 좋은' 구조가 아니다. Richards-Ford의 "모든 것은 트레이드오프" 제1법칙이 가장 강하게 적용되는 스타일이다. 이점(독립성)을 얻기 위해 분산의 비용(복잡성, 일관성 약화, 관측성 부담)을 감수하는 선택이다.
설계 사례 — 모놀리스에서 서비스 분해
전자상거래 시스템을 모놀리스에서 마이크로서비스로 옮기는 과정을 본다.
1단계 — 모놀리스 (단일 DB)
class OrderService {
void placeOrder(OrderRequest req) {
// orders, payments, inventory, shipping 테이블을 한 트랜잭션에서 직접 조작
Order order = new Order(req);
orderRepo.save(order);
paymentRepo.save(new Payment(order)); // 같은 DB, 같은 트랜잭션
inventoryRepo.decrement(req.items());
shippingRepo.save(new Shipment(order));
}
}
ACID 트랜잭션 하나로 모든 변경이 원자적으로 일어난다. 단순하지만, 결제·재고·배송이 한 프로세스에 묶여 결제가 느려지면 전체가 블록된다.
2단계 — 서비스 분리 (그러나 DB 공유 — 분산 모놀리스)
// Order Service (별도 프로세스)
class OrderService {
private final JdbcTemplate jdbc; // 같은 DB에 접근
void placeOrder(OrderRequest req) {
Order order = new Order(req);
jdbc.update("INSERT INTO orders ...");
// 다른 서비스의 테이블에 직접 insert
jdbc.update("INSERT INTO payments ...");
// Inventory Service를 HTTP로 호출
inventoryClient.decrement(req.items());
}
}
프로세스는 분리됐지만 Order Service가 payments 테이블에 직접 insert한다. Payments Service가 payments 테이블 스키마를 바꾸면 Order Service가 깨진다. 외견상 마이크로서비스지만, 결합도는 모놀리스와 비슷하다 — 분산 모놀리스. 이 상태는 Newman이 경고하는 가장 흔한 실패 패턴이다.
3단계 — 서비스별 DB (진정한 마이크로서비스)
// Order Service — 오직 orders DB만
class OrderService {
private final OrderRepo repo; // 자기 DB만
private final PaymentClient payment; // Payment Service API
private final InventoryClient inventory; // Inventory Service API
private final EventPublisher events; // 비동기 이벤트
@Transactional
public OrderId placeOrder(OrderRequest req) {
Order order = new Order(req);
order.markPending(); // 결제 대기 상태로 저장
repo.save(order);
events.publish(new OrderPlacedEvent(order.id(), order.total(), req.items()));
// 결제·재고는 이벤트 구독자가 비동기 처리
return order.id();
}
}
Order Service는 자기 DB만 건드리고, 결제·재고는 이벤트로 알린다. Payment Service·Inventory Service가 이 이벤트를 구독해 자기 DB를 업데이트한다. 각 서비스가 자기 DB를 독점한다 — 스키마 변경이 다른 서비스에 영향을 주지 않는다.
flowchart LR
OS[Order Service<br/>+ orders DB] -->|OrderPlacedEvent| MQ[(Message Broker)]
MQ --> PS[Payment Service<br/>+ payments DB]
MQ --> IS[Inventory Service<br/>+ inventory DB]
MQ --> SS[Shipping Service<br/>+ shipping DB]
OS x-- "DB 직접 접근 없음" --x PS
이 구조의 대가 — 결제가 즉시 완료되지 않는다. '주문 완료'와 '결제 완료'가 분리되고, 중간 상태('결제 대기 중')가 사용자에게 보인다. 이것이 '최종 일관성(eventual consistency)'을 감수하는 의미다. 분산 트랜잭션이 필요한 부분은 Saga 패턴으로 처리한다 (07편 참조).
언제 마이크로서비스가 적합한가
Newman의 2판은 "언제 가야 하나"보다 "아직 가지 말아야 할 때"를 더 강조한다.
마이크로서비스가 적합할 조건:
- 조직이 여러 팀으로 나뉘고 각 팀이 독립 배포 주기를 원할 때 (Conway 정렬)
- 시스템이 충분히 커서 모놀리스의 배포·확장이 병목일 때
- 부하가 서비스별로 극단적으로 다를 때 (결제는 트래픽 폭증, 배송은 안정적)
- 도메인 경계가 충분히 명확해서 서비스가 자연스럽게 떨어질 때
- CI/CD·관측성 인프라가 성숙할 때 — 이게 없으면 마이크로서비스 운영이 지옥
마이크로서비스를 피해야 할 때:
- 팀이 하나이거나 소수 — Conway 정렬이 안 됨
- 도메인이 아직 불명확한 초기 제품 — 경계 잘못 그으면 옮기기 비쌈
- CI/CD·분산 추적 인프라가 없음 — 운영 복잡성 감당 불가
- 강한 일관성(ACID)이 비즈니스 핵심 — 최종 일관성 감수 불가
마지막 조건이 흔히 간과된다. 금융 원장처럼 '강한 일관성'이 비즈니스 핵심인 시스템에서 마이크로서비스의 최종 일관성은 큰 위험을 만든다. 이런 시스템에선 모놀리스나 모듈형 모놀리스가 더 안전한 출발점이다.
다음으로 — 함정과 비교
마이크로서비스를 도입하겠다며 자르는 일은 시작에 불과하다. 자르고 난 뒤의 함정 — 분산 모놀리스, 동기 호출 체인, 관측성 부담, Conway 미정렬 — 은 06편(마이크로서비스의 함정)에서 다룬다. 그리고 12편(스타일 비교)에서는 같은 요구사항을 두고 모놀리스·계층형·헥사고날·마이크로서비스·이벤트 기반 중 어느 쪽이 적합한지 비교한다.
마이크로서비스의 약속은 '독립성'이다. 그 약속을 지키려면 — 서비스별 DB, 독립 배포, 비즈니스 능력 기반 분해 — 이 세 가지가 진짜로 강제돼야 한다. 한 가지라도 빠지면 마이크로서비스의 형태만 흉내 낸 분산 모놀리스가 된다.
참고
- Newman — (2nd ed, O'Reilly, 2021), Ch.1·2·3 (분해 기준)·4 (데이터 격리) — 접근 2026-07-20
- Fowler, Lewis — "Microservices" (martinfowler.com, 2014), https://martinfowler.com/articles/microservices.html — 접근 2026-07-20
- Evans — (Addison-Wesley, 2003), 바운디드 컨텍스트 장
- Richards, Ford — (O'Reilly, 2020), 마이크로서비스 장
'Software Architecture > Architectural Styles' 카테고리의 다른 글
| Architectural Styles - 07. 이벤트 기반 아키텍처 (0) | 2026.07.20 |
|---|---|
| Architectural Styles - 06. 마이크로서비스의 함정 (0) | 2026.07.20 |
| Architectural Styles - 04. 클린 아키텍처 (0) | 2026.07.20 |
| Architectural Styles - 03. 헥사고날 아키텍처 (0) | 2026.07.20 |
| Architectural Styles - 02. 계층형 아키텍처 (0) | 2026.07.20 |