마이크로서비스 패턴은 이름과 다이어그램만 봐서는 실제 Java/Spring 코드로 어떻게 옮기는지 감이 잡히지 않습니다. 잘못된 패턴을 잘못된 곳에 적용하면 모놀리스보다 느리고 디버깅 비용이 3배 늘어납니다.
오래 개발하면서 Java/Spring 백엔드를 운영해온 관점에서 10가지 패턴을 코드와 함께 정리했습니다. 정독하면 본인 시스템에 어떤 패턴이 필요한지와 Spring Cloud·Resilience4j·Kafka로 어떻게 구현하는지까지 이해됩니다.

한눈에 — 마이크로서비스 패턴 10가지 + Java/Spring 매핑
각 마이크로서비스 패턴은 해결하는 문제가 명확히 다릅니다. 모든 패턴을 다 적용할 필요는 없고, 본인 시스템 규모에 맞게 골라 씁니다.
| # | 패턴 | 해결 문제 | Java/Spring 구현 | 필수도 |
|---|---|---|---|---|
| 1 | Database Per Service | 서비스 간 DB 결합 | Spring Data + 멀티 데이터소스 | ★★★ |
| 2 | API Gateway | 클라이언트→서비스 라우팅 | Spring Cloud Gateway | ★★★ |
| 3 | Backend For Frontend (BFF) | 클라이언트별 다른 응답 | Spring Cloud Gateway + 별도 BFF | ★★ |
| 4 | CQRS | 읽기·쓰기 분리 | Axon Framework 또는 직접 분리 | ★★ |
| 5 | Event Sourcing | 상태 변경 이력 보존 | Spring + Kafka + EventStore | ★★ |
| 6 | Saga | 분산 트랜잭션 | Spring + Kafka 또는 Axon | ★★★ |
| 7 | Sidecar | 횡단 관심사 분리 | Istio·Linkerd (Spring 외부) | ★★ |
| 8 | Circuit Breaker | 장애 전파 차단 | Resilience4j + Spring Cloud | ★★★ |
| 9 | Anti-Corruption Layer | 외부 시스템 격리 | Adapter Pattern + Spring | ★★ |
| 10 | Aggregator | 여러 서비스 응답 합성 | Spring Cloud Function 또는 직접 | ★★ |
→ 신규 마이크로서비스 시작 시 필수 3개: API Gateway · Database Per Service · Circuit Breaker. 나머지는 규모·요구사항에 따라 점진 도입.
1. Database Per Service — JPA 멀티 데이터소스
문제: 모든 서비스가 같은 DB를 쓰면 한 서비스가 DB 스키마 바꿀 때 다른 서비스 깨짐.
해결: 각 서비스가 독립 DB. Spring Data JPA로 멀티 데이터소스 분리.
@Configuration
@EnableJpaRepositories(
basePackages = "com.order.repository",
entityManagerFactoryRef = "orderEntityManager",
transactionManagerRef = "orderTransactionManager"
)
public class OrderDbConfig {
@Bean
@ConfigurationProperties("spring.datasource.order")
public DataSource orderDataSource() {
return DataSourceBuilder.create().build();
}
}
서비스마다 같은 패턴 반복. 단점은 서비스 간 조인 불가 — 데이터 합성은 Aggregator 패턴(10번)으로 해결.
2. API Gateway — Spring Cloud Gateway
문제: 클라이언트가 10개 마이크로서비스 주소를 다 알아야 함.
해결: API Gateway가 단일 진입점. 라우팅·인증·rate limiting 처리.
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("order-service", r -> r.path("/api/orders/**")
.filters(f -> f.stripPrefix(1)
.addRequestHeader("X-Request-Id", UUID.randomUUID().toString()))
.uri("lb://order-service"))
.route("payment-service", r -> r.path("/api/payments/**")
.filters(f -> f.circuitBreaker(c -> c.setName("payment-cb")))
.uri("lb://payment-service"))
.build();
}
lb://는 Eureka·Consul로 서비스 디스커버리 연결. Circuit Breaker(8번)를 여기서 한 번에 적용합니다.
3. Backend For Frontend (BFF) — 클라이언트별 다른 응답
문제: 웹·iOS·Android 클라이언트마다 필요한 데이터 형태가 다른데 같은 API로 강제.
해결: 클라이언트별 별도 BFF 서비스. iOS-BFF는 iOS가 필요한 응답만, Web-BFF는 웹용으로 가공.
API Gateway와 비슷해 보이지만 차이는: Gateway는 라우팅·횡단 관심사, BFF는 클라이언트 맞춤 응답 가공. 보통 같이 씁니다 — Gateway → BFF → 내부 서비스.
4. CQRS — 읽기·쓰기 분리
문제: 쓰기는 일관성, 읽기는 성능이 핵심인데 같은 모델 쓰면 둘 다 어중간.
해결: 쓰기 모델(Command)과 읽기 모델(Query) 분리. Spring + Axon Framework가 표준.
@CommandHandler
public OrderAggregate handle(CreateOrderCommand cmd) {
apply(new OrderCreatedEvent(cmd.getOrderId(), cmd.getItems()));
return this;
}
@EventHandler
public void on(OrderCreatedEvent event) {
// 읽기용 비정규화 DB에 저장 (Elasticsearch 등)
orderViewRepository.save(new OrderView(event));
}

복잡해서 신규 프로젝트에 처음부터 도입은 비추. 읽기 부하가 쓰기보다 10배+ 일 때 도입.
5. Event Sourcing — 상태 변경 이력 보존
문제: 현재 상태만 저장하면 "어제 17시에 왜 가격이 바뀌었나" 같은 추적 불가.
해결: 모든 변경을 이벤트로 저장. 현재 상태는 이벤트 누적 결과.
@Aggregate
public class OrderAggregate {
@AggregateIdentifier private String orderId;
private OrderStatus status;
@EventSourcingHandler
public void on(OrderCreatedEvent event) {
this.orderId = event.getOrderId();
this.status = OrderStatus.CREATED;
}
@EventSourcingHandler
public void on(OrderPaidEvent event) {
this.status = OrderStatus.PAID;
}
}
감사·규정 준수 필요한 환경(금융·의료)에서 강력합니다. 일반 CRUD에는 오버킬.
6. Saga — 분산 트랜잭션
문제: 주문 서비스가 결제·재고·배송 서비스 호출 중 한 곳 실패 시 롤백 처리.
해결: Saga 패턴 — 각 단계마다 보상 트랜잭션 정의. Spring + Kafka 또는 Axon으로 구현.
@SagaEventHandler(associationProperty = "orderId")
public void on(OrderCreatedEvent event) {
commandGateway.send(new ReservePaymentCommand(event.getOrderId(), event.getAmount()));
}
@SagaEventHandler(associationProperty = "orderId")
public void on(PaymentFailedEvent event) {
// 보상: 주문 취소
commandGateway.send(new CancelOrderCommand(event.getOrderId()));
}
한국 결제 통합에서 거의 필수 — 토스페이먼츠·포트원 호출 후 실패 시 주문 자동 취소.
7. Sidecar — 횡단 관심사 분리
문제: 로깅·메트릭·인증을 모든 서비스에 박으면 중복 코드 폭증.
해결: 사이드카 컨테이너(같은 Pod 안 별도 컨테이너)가 횡단 관심사 처리. Istio·Linkerd 같은 Service Mesh가 표준.
Java/Spring 코드는 변하지 않음 — 사이드카가 네트워크 레벨에서 처리. 단, Kubernetes 환경 전제.
8. Circuit Breaker — 장애 전파 차단 (필수)
문제: 결제 서비스 장애 시 주문 서비스도 같이 멈춤 (장애 도미노).
해결: 호출 실패율 임계 넘으면 자동으로 호출 차단 (Fallback). Resilience4j + Spring Cloud가 표준.
@CircuitBreaker(name = "payment", fallbackMethod = "paymentFallback")
public PaymentResult callPayment(Order order) {
return paymentClient.process(order);
}
public PaymentResult paymentFallback(Order order, Exception e) {
// 폴백: 큐에 저장 후 나중에 재시도
paymentQueue.enqueue(order);
return PaymentResult.pending();
}

설정 핵심: 실패율 50% 넘으면 30초간 차단, 그 후 부분 재개. application.yml로 조정.
9. Anti-Corruption Layer — 외부 시스템 격리
문제: 레거시 시스템·외부 API의 데이터 모델이 우리 모델과 다른데 그대로 받으면 코드 오염.
해결: Anti-Corruption Layer (ACL) = 외부 모델을 우리 모델로 변환하는 어댑터.
@Component
public class LegacyOrderAdapter {
public Order toInternalOrder(LegacyOrderDto legacy) {
// 외부 모델 → 내부 모델 변환
return Order.builder()
.id(legacy.getOrderNo()) // 필드명 다름
.amount(legacy.getPrice() / 100.0) // 단위 변환
.build();
}
}
한국 공공 API·은행 API 연동에서 거의 필수. 외부 시스템 변경이 우리 도메인을 오염시키지 않음.
10. Aggregator — 여러 서비스 응답 합성
문제: 클라이언트가 주문 정보 + 결제 상태 + 배송 상태를 한 번에 받고 싶은데 3번 호출해야 함.
해결: Aggregator 서비스가 3개 서비스 동시 호출 후 합성된 응답 반환. Spring WebClient 비동기 호출이 표준.
public Mono<OrderDetail> getOrderDetail(String orderId) {
Mono<Order> order = orderClient.get(orderId);
Mono<Payment> payment = paymentClient.get(orderId);
Mono<Delivery> delivery = deliveryClient.get(orderId);
return Mono.zip(order, payment, delivery)
.map(tuple -> new OrderDetail(tuple.getT1(), tuple.getT2(), tuple.getT3()));
}
Mono.zip으로 3개 호출 병렬 실행. 순차 호출보다 응답 시간 1/3.
마이크로서비스 패턴 선택 매트릭스 — 어떤 패턴을 언제 쓰나
| 상황 | 적용 패턴 |
|---|---|
| 신규 마이크로서비스 시작 | 1, 2, 8 (DB 분리·Gateway·Circuit Breaker) |
| 한국 결제·외부 API 연동 | 6, 9 (Saga·ACL) |
| 모바일·웹 클라이언트 분리 | 3 (BFF) |
| 읽기 부하 큼 | 4 (CQRS) |
| 감사·규정 준수 (금융·의료) | 5 (Event Sourcing) |
| Kubernetes 기반 운영 | 7 (Sidecar) |
| 응답 시간 단축 | 10 (Aggregator) |
흔한 함정 3가지
1. 한 번에 10개 마이크로서비스 패턴 다 적용하는 함정
신규 시스템에 10개 다 박으면 개발 속도 1/3 + 디버깅 5배. 1·2·8 (DB 분리·Gateway·Circuit Breaker)만 시작하고 필요할 때 추가하세요.
2. CQRS·Event Sourcing 오버엔지니어링
읽기·쓰기 부하 차이가 10배 미만이면 CQRS는 오버킬. Event Sourcing은 더 신중 — 일반 CRUD는 그냥 JPA가 더 빠릅니다. 정말 필요한지 비즈니스 요구로 검증 후 도입.
3. Circuit Breaker 임계값 잘못 설정
기본값 50%로 두면 트래픽 적은 새벽에 한 번 실패로 차단되는 경우 흔합니다. 최소 호출 횟수(minimumNumberOfCalls)를 50~100으로 설정해 통계 신뢰도 확보 필요.
Q&A — 자주 보는 질문 5개
Q. Spring Cloud Gateway vs Zuul 어느 게 표준인가요?
A. Spring Cloud Gateway가 현재 표준입니다. Zuul은 Netflix가 유지보수 중단 상태. 신규 프로젝트는 Gateway, 레거시면 점진 마이그레이션 권장.
Q. Saga 구현 Axon Framework vs Kafka 직접 어느 게 좋나요?
A. 5~10명 팀이면 Axon이 빠름 (보일러플레이트 ↓). 50명+ 팀이거나 멀티 언어 환경이면 Kafka 직접 구현이 유연. Axon은 학습 곡선 약간 있음.
Q. Resilience4j 외에 Hystrix 쓰면 안 되나요?
A. Hystrix는 유지보수 중단(Netflix 공식). Resilience4j가 표준. Hystrix 코드 있으면 마이그레이션 권장.
Q. CQRS 도입했는데 결과적 일관성(Eventual Consistency)이 비즈니스에 안 맞으면?
A. CQRS 빼는 게 답입니다. CQRS는 일관성 약화를 받아들이는 전제. "고객이 주문 직후 주문 목록에서 안 보임" 같은 사용자 불편이 비즈니스 손실보다 크면 도입 후회. 도입 전 비즈니스 시뮬레이션 필수.
Q. 한국 환경에서 Service Mesh(Istio·Linkerd) 도입 사례 있나요?
A. 대기업 IT(쿠팡·우아한형제들 등)·대형 SaaS에서 도입. 5명 안쪽 팀에는 오버킬 — Spring Cloud + Resilience4j로 충분. Service Mesh는 100명+ 조직·100+ 서비스에서 검토.
정리 — 신규 시스템 시작 시 패턴 도입 순서
| 단계 | 패턴 | 시점 |
|---|---|---|
| 1 | API Gateway (#2) | 서비스 2개 이상 |
| 2 | Database Per Service (#1) | 서비스 분리와 동시 |
| 3 | Circuit Breaker (#8) | 외부 호출 시작 |
| 4 | Saga (#6) | 분산 트랜잭션 필요 시 |
| 5 | Anti-Corruption Layer (#9) | 외부 API 연동 시 |
| 6 | Aggregator (#10) | 응답 합성 필요 시 |
| 7 | BFF (#3) | 클라이언트 다양화 시 |
| 8 | CQRS (#4) | 읽기 부하 폭증 시 |
| 9 | Event Sourcing (#5) | 감사·규정 필수 시 |
| 10 | Sidecar (#7) | Kubernetes 도입 시 |

마이크로서비스 패턴은 다 외울 필요 없습니다. 신규 시스템은 1·2·8부터 시작하고 비즈니스 요구가 생길 때 하나씩 추가하세요. 비슷한 환경이면 위 순서대로 따라가도 무리 없습니다.
검증 환경: Spring Boot 3.4, Spring Cloud 2024.0.x, Resilience4j 2.2.x, Axon Framework 4.10.x, Java 21 LTS
원본 발행: 2025-03-04 / 2026-06-09 전면 개정
'IT > Information' 카테고리의 다른 글
| Windows 11 개발 환경 세팅 — 14가지 필수 설치 체크리스트 (2026) (0) | 2026.05.12 |
|---|---|
| Vercel 침해 사고 분석 — Context.ai 공급망 공격으로 본 SaaS 보안 점검 5가지 (0) | 2026.04.28 |
| 시니어 개발자들이 절대 놓치지 않는 10가지 코딩 습관 (0) | 2024.11.22 |
| 꼭 알아야 할 시스템 설계 용어 50가지 (4) | 2024.11.07 |
| Backend for Frontend (BFF) Architecture (2) | 2024.10.24 |
IT 기술과 개발 내용을 포스팅하는 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!