소프트웨어 아키텍처

내고장성과 복원력

meellon 2026. 7. 3. 05:20

학습 목표

분산 환경에서 부분 장애전체로 퍼지는 이유를 설명할 수 있다.

타임아웃·재시도·지수 백오프를 설계할 수 있다.

Circuit breaker 상태와 bulkhead격리하는 방식을 설명할 수 있다.

Fallback·graceful degradation을 아키텍처 결정으로 문서화할 수 있다.

문제 상황

  • Payment 500ms인데 Order thread 200개가 Payment 무한 대기 — Order 전체 멈춤
  • Payment 복구 후 재시도 폭주 — Payment 다시 다운 (retry storm)
  • Inventory 장애인데 Catalog까지 503동기 체인 6 hop, timeout 없음
  • Circuit breaker open인데 caller가 계속 호출 — breaker 의미 없음
  • 알림 실패가 주문 실패 — 핵심·부가 경계 없음
  • K8s pod healthy인데 thread pool 100%liveness만 보고 ready 무시

동기·비동기·saga까지 봤다. 장애가 나도 서비스가 부분적으로 살아남게 설계하는 편이다.

1. 복원력이란

복원력(Resilience) — 장애·부하 스파이크·느린 의존성 속에서도 핵심 기능허용 가능 수준으로 유지.

실패 모드 증상
Cascading failure A down → B 대기 → B down → C…
Retry storm 복구 직후 동시 재시도로 재장애
Resource exhaustion thread·connection·memory 고갈
Slow dependency latency 합산·queue buildup
  • 가용성 QA — "100% up"이 아니라 degraded설계 대상
  • OS — blocking I/O·thread 대기; Network — TCP timeout; 여기서는 서비스 레벨 패턴

2. 타임아웃

타임아웃 — 기다림에 상한. 없으면 영원히 점유.

계층
Client HTTP client 3s
Service downstream RPC 2s
DB query timeout 1s
LB / mesh idle·per-try timeout

설계 원칙

  • End-to-end budget — 사용자 체감 3s면 hop 나눠 할당
  • Shorter downstream — 바깥 ≥ 안쪽 합 (여유 포함)
  • Cancel propagation — 상위 timeout 시 하위 요청 취소 (가능하면)
  • Timeout ≠ 즉시 실패 처리 — retry·fallback함께
# conceptual client timeouts
http:
  connect_timeout: 500ms
  read_timeout: 2s
downstream:
  payment_rpc: 1500ms
  inventory_rpc: 800ms
  • 무한 RestTemplate· JDBC — 명시 timeout 없으면 사고 후보

3. 재시도

재시도일시 오류(네트워크 blip, 503)에 재호출.

재시도 OK 재시도 금지
Idempotent read non-idempotent write (중복 결제)
503·connection reset 400·401·404 (클라이언트 오류)
짧은 blip 지속 down (breaker로 전환)

지수 백오프 + jitter

attempt 1 → wait 100ms ± jitter
attempt 2 → wait 200ms
attempt 3 → wait 400ms
max attempts 3
  • Jitter — 동시 재시도 분산 (retry storm 방지)
  • 멱등 키Idempotency-Key header, DB unique constraint
  • Dead letter — N회 실패 → 사람·배치 (비동기 편)

4. Circuit breaker

Circuit breaker — 의존성 연속 실패호출 차단자원·연쇄 방지.

상태 동작
Closed 정상 호출, 실패 카운트
Open 즉시 fail fast (또는 fallback), probe 대기
Half-open 소수 trial — 성공 시 Closed, 실패 시 Open
circuit_breaker:
  name: payment
  failure_rate_threshold: 50%
  sliding_window: 10
  wait_duration_in_open: 30s
  permitted_calls_in_half_open: 3
  fallback: degraded_checkout
  • Caller·library·sidecar(mesh) 어디에 둘지 — 일관 적용
  • Open 중에도 큐잉하면 thread 고갈 — fail fast가 목적
  • Half-open 없으면 복구 감지 늦음

5. Bulkhead

Bulkhead(격벽)자원 풀 분리 — 한 의존성이 다른 풀을 고갈시키지 않음.

bulkhead
Thread pool payment pool 20 · catalog pool 50
Connection pool DB per service limit
Semaphore 동시 downstream N
Pod / cell AZ·shard blast radius
Order service
  pool A (20 threads) → Payment sync
  pool B (30 threads) → Inventory sync
  pool C (10 threads) → internal DB
  • Payment 느림 → pool A만 포화, pool B·C는 주문 조회 가능
  • MSA 7편 장애 격리 다이어그램 — 같은 bulkhead 아이디어, 이번 편은 패턴 심화
  • K8s requests/limits·HPA — 프로세스 bulkhead와 맞물림

6. Fallback과 degradation

전략
Cache fallback 추천 API down → 캐시 피드
Default value 환율 실패 → 어제 rate + 배너
Queue later 알림 실패 → outbox 재전송
Feature off 리뷰 일시 비표시
  • Fallback 비즈니스 승인 — "결제 없이 주문"은 안 됨
  • 관측 — degraded 비율·breaker open 알람

7. 실무 체크리스트

질문 좋은 답
모든 outbound timeout? connect + read 명시
Retry 몇 번·backoff? 문서화 + jitter
Write retry 멱등? key·constraint
Downstream breaker? failure rate·half-open
Pool 분리? bulkhead per dependency
부가 실패가 핵심 막나? async·fallback
조합 효과
timeout + retry + breaker 단계 방어
bulkhead + async side effect 핵심 path 보호
breaker + fallback 사용자 degraded 경험
  • Chaos engineering — breaker·bulkhead 검증 (Platform 편과 연계)
  • Part 4 마무리 — 분산 = 장애 전제 + 통신 + 일관성 + 복원력

8. 정리

  • Timeout — 무한 대기 금지, budget 분배
  • Retry — idempotent·backoff·jitter, storm 주의
  • Circuit breaker — fail fast, Closed/Open/Half-open
  • Bulkhead — pool 분리, 연쇄 고갈 방지
  • Fallback — 비즈니스 허용 범위만
  • 다음 — 데이터 저장소 선택 (Part 5)

다음에 다룰 것

  • 데이터 저장소 선택
  • RDB vs NoSQL, workload별 선택 기준

해당 내용은 Fundamentals of Software Architecture (Mark Richards, Neal Ford) 및 Release It! (Michael Nygard) 의 내용을 기반으로 합니다.

'소프트웨어 아키텍처' 카테고리의 다른 글

캐싱 전략  (0) 2026.07.05
데이터 저장소 선택  (0) 2026.07.04
동기 vs 비동기 통신  (0) 2026.07.02
CAP과 일관성 모델  (0) 2026.07.01
분산 시스템 기초  (0) 2026.06.30