Post

확장성 패턴 기본기

처리량·지연·팬아웃으로 확장 문제를 분해하고 LB, 파이프/필터, 스캐터-개더, 오케스트레이션/코레오그래피 선택 기준 정리

확장성 패턴 기본기

한 문단 요약 — 확장성 문제는 하나가 아니라 세 가지다

결론: 확장성 문제는 처리량(throughput), 지연(latency), 팬아웃(fan-out) 세 축으로 분해해야 판단이 가능하다.
처리량은 “얼마나 많이 동시에 처리할 수 있는가”의 문제다.
지연은 평균이 아니라 꼬리 지연(tail latency)이 SLA를 깨뜨리는 문제다.
팬아웃은 하나의 요청이 몇 개의 의존 호출로 분해되는가의 문제다.
확장성 패턴은 이 세 문제 중 무엇을 희생하고 무엇을 지킬지 선택하는 도구다.


공통 예시 시나리오

결론: 모든 패턴은 같은 요청을 어떻게 나누고 다시 모으는가의 차이다.

하나의 요청:
“상품 검색 API”
→ 개인화 추천 조회
→ 재고 확인
→ 결과 조합 후 응답

이 단일 흐름을 끝까지 재사용한다.


Load Balancing

결론: Load Balancing은 처리량 확장의 출발점이지, 지연 문제의 해답은 아니다.

정의

여러 인스턴스로 들어오는 요청을 분산하는 패턴.

직관

여러 계산대에 줄을 나누어 세운다.

동작 흐름

Client
→ Load Balancer
→ Search API 인스턴스 N개 중 하나
→ 응답

장점 / 단점

장점단점
처리량 수평 확장지연 감소 보장 안 됨
단순한 구조느린 인스턴스에 발목 잡힘
장애 격리 일부 가능상태 공유 시 효과 감소

실패 모드

  • 느린 인스턴스로 인한 tail latency
  • 세션/캐시 상태 공유로 인한 병목

언제 쓰는가

  • 요청이 독립적이고 균질할 때
  • 상태를 외부로 분리했을 때

언제 쓰지 말아야 하는가

  • 요청별 처리 시간이 크게 다를 때
  • 팬아웃 문제를 해결하려 할 때

적용 체크리스트

  • 상태는 외부 저장소에 있는가?
  • 헬스 체크 기준이 명확한가?
  • 느린 인스턴스를 배제할 수 있는가?
  • 오토스케일 조건이 명확한가?
  • LB 자체가 병목이 아닌가?

Pipes & Filters

결론: Pipes & Filters는 단계별 책임 분리와 병렬 처리를 가능하게 하지만, 상태 공유 순간 무너진다.

정의

요청 처리를 여러 단계(filter)로 분리해 파이프라인으로 연결하는 패턴.

직관

조립 라인에서 부품이 단계별로 이동한다.

동작 흐름

Request
→ 검색 Filter
→ 추천 Filter
→ 재고 Filter
→ 응답

장점 / 단점

장점단점
단계별 확장/교체 용이전체 지연 증가
병렬 처리 가능상태 공유 시 결합도 폭발
테스트 용이디버깅 난이도 상승

실패 모드

  • 파이프 중간 지연 누적
  • 필터 간 암묵적 상태 의존

언제 쓰는가

  • 단계별 책임이 명확할 때
  • 각 단계가 독립적으로 확장 가능할 때

언제 쓰지 말아야 하는가

  • 필터 간 강한 상태 공유가 필요할 때

적용 체크리스트

  • 각 필터가 순수 함수에 가까운가?
  • 실패 시 중단/폴백 전략이 있는가?
  • 병렬화 가능한 단계는 무엇인가?
  • 관측 지점이 명확한가?
  • 필터 추가 비용을 예측했는가?

Scatter-Gather

결론: Scatter-Gather는 팬아웃 문제를 해결하지만, 지연과 실패를 증폭시킨다.

정의

요청을 여러 하위 요청으로 분산(scatter)하고 결과를 모아(gather) 응답하는 패턴.

직관

여러 팀에 동시에 질문하고 답을 취합한다.

동작 흐름

Request
→ 검색 서비스
→ 추천 서비스
→ 재고 서비스 (병렬)
→ 결과 조합
→ 응답

장점 / 단점

장점단점
응답 병렬화tail latency 증가
기능 분리부분 실패 처리 복잡
유연한 조합타임아웃 설계 필수

실패 모드

  • 하나의 느린 호출로 전체 지연
  • 일부 실패로 전체 실패 전파

언제 쓰는가

  • 하위 호출들이 독립적일 때
  • 일부 결과 누락을 허용할 때

언제 쓰지 말아야 하는가

  • 모든 하위 결과가 필수일 때
  • 타임아웃/폴백 설계가 없을 때

적용 체크리스트

  • 타임아웃 기준이 명확한가?
  • 부분 성공을 허용하는가?
  • 결과 조합 로직이 단순한가?
  • 호출 수 상한이 있는가?
  • 장애 격리가 가능한가?

Execution Orchestrator

결론: Orchestrator는 흐름 제어를 중앙집중화하는 대신, 책임과 위험도 함께 모은다.

정의

중앙 컴포넌트가 전체 호출 순서와 분기를 제어하는 패턴.

직관

지휘자가 각 연주 타이밍을 통제한다.

동작 흐름

Request
→ Orchestrator
→ 검색
→ 추천
→ 재고
→ 응답

장점 / 단점

장점단점
흐름 가시성 높음SPOF 위험
복잡한 분기 처리 용이확장 부담 집중
디버깅 쉬움변경 시 영향 큼

실패 모드

  • Orchestrator 장애로 전체 중단
  • 과도한 책임 집중

언제 쓰는가

  • 흐름이 복잡하고 조건 분기가 많을 때
  • 중앙 관측이 중요한 경우

언제 쓰지 말아야 하는가

  • 단순 병렬 호출만 필요한 경우

적용 체크리스트

  • Orchestrator 이중화가 되어 있는가?
  • 타임아웃/재시도 정책이 있는가?
  • 책임 범위가 명확한가?
  • 상태 관리 전략이 있는가?
  • 부하 집중을 감당할 수 있는가?

Choreography

결론: Choreography는 결합도를 낮추는 대신, 흐름 가시성을 포기한다.

정의

각 서비스가 이벤트에 반응하며 자율적으로 다음 단계를 수행하는 패턴.

직관

약속된 신호에 맞춰 각자가 움직인다.

동작 흐름

검색 완료 이벤트
→ 추천 서비스 반응
→ 재고 서비스 반응
→ 결과 이벤트

장점 / 단점

장점단점
결합도 최소화흐름 파악 어려움
확장 용이디버깅 난이도 높음
SPOF 감소일관성 관리 어려움

실패 모드

  • 이벤트 누락/중복
  • 흐름 추적 불가

언제 쓰는가

  • 서비스 간 독립성이 중요할 때
  • 비동기 처리 허용 시

언제 쓰지 말아야 하는가

  • 강한 순서 보장이 필요할 때

적용 체크리스트

  • 이벤트 계약이 명확한가?
  • 중복 처리 대비가 되어 있는가?
  • 흐름 추적 도구가 있는가?
  • 장애 시 복구 전략이 있는가?
  • 운영 팀이 이해 가능한가?

Orchestrator vs Choreography

결론: 선택 기준은 흐름 복잡도 vs 결합도 허용치다.

기준OrchestratorChoreography
흐름 가시성높음낮음
결합도높음낮음
장애 반경분산
운영 난이도높음
변경 비용분산

흔한 설계 실수

결론: 확장성 실패는 대부분 보조 설계 부재에서 발생한다.

  1. Scatter-Gather 후 타임아웃/폴백 없음
  2. Pipes & Filters에서 상태 공유로 결합도 폭발
  3. Orchestrator를 단일 장애점으로 방치

패턴 선택 질문 7개

  1. 동기인가 비동기인가?
  2. 팬아웃 호출 수는 몇 개인가?
  3. 일부 실패를 허용하는가?
  4. SLA는 평균인가 최악인가?
  5. 관측 가능성이 중요한가?
  6. 변경 빈도는 높은가?
  7. 운영 팀 역량은 충분한가?

재학습 체크리스트

  1. 확장 문제를 세 가지로 분해했는가?
  2. 팬아웃 수를 수치로 말할 수 있는가?
  3. tail latency 대응이 있는가?
  4. 타임아웃 기준이 명확한가?
  5. 폴백 전략이 있는가?
  6. SPOF를 인지했는가?
  7. 운영 부담을 고려했는가?
  8. 패턴 조합 가능성을 검토했는가?
  9. 트래픽 성장 시나리오가 있는가?
  10. “왜 이 패턴인가”를 설명할 수 있는가?

This post is licensed under CC BY 4.0 by the author.