Circuit Breaker Bulkhead 장애 격리
3줄 요약
- Circuit Breaker와 Bulkhead는 외부 의존성의 실패가 애플리케이션 전체 스레드, 커넥션, queue를 잠식하지 않게 하는 장애 격리 장치다.
- Circuit Breaker는 실패하거나 느린 호출을 잠시 차단하고 회복을 시험하며, Bulkhead는 리소스 풀을 나누어 한 기능의 장애가 다른 기능을 굶기지 않게 한다.
- Fallback과 Degradation은 가짜 성공이 아니라 사용자가 어떤 기능이 축소되었는지 이해하고, 운영자가 장애 범위를 추적할 수 있게 하는 API 계약이다.
핵심 정리
- Cascading Failure는 한 의존성의 지연이 호출자를 기다리게 하고, 그 대기가 스레드와 커넥션을 붙잡아 다른 정상 기능까지 느리게 만드는 현상이다.
- Timeout은 기본 방어선이다. 무한 대기를 끊지 않으면 Circuit Breaker와 Bulkhead가 있어도 리소스 고갈을 늦게 발견한다.
- Circuit Breaker는
closed, open, half-open 상태를 오가며 실패율, slow call 비율, 최소 호출 수, open 유지 시간으로 판단한다.
- Bulkhead는 스레드 풀, semaphore, connection pool, queue, consumer group 같은 리소스를 분리한다. 격리할수록 장애 전파는 줄지만 운영할 풀과 지표가 늘어난다.
- Fallback은 캐시, 부분 응답, pending, 기본값, 기능 숨김 중 어떤 경험을 줄지 정하는 설계다. 결제나 재고처럼 틀리면 안 되는 값에는 함부로 쓰면 안 된다.
- Resilience4j 설정은 annotation을 붙이는 일이 아니라 timeout, retry, circuit breaker, bulkhead, fallback 순서와 metric을 함께 설계하는 일이다.
- 대표 지표는
slow call rate, failure rate, open circuit count, bulkhead rejected count, fallback rate, downstream latency다.
헷갈리는 지점
- Circuit Breaker를 timeout 대체재로 생각하기 쉽다. Circuit Breaker는 반복 실패를 차단하는 장치이고, 개별 호출의 최대 대기 시간은 timeout이 끊어야 한다.
- 핵심은 timeout, retry, circuit breaker, bulkhead가 각각 다른 실패를 다룬다는 점이다.
- Fallback을 성공 응답으로 포장하기 쉽다. 사용자가 틀린 정보를 믿으면 장애보다 더 큰 정합성 문제가 된다.
- 핵심은 fallback 응답에 데이터 출처, 오래됨, 기능 축소 상태가 드러나야 한다는 점이다.
- Bulkhead를 스레드 풀 분리로만 이해하기 쉽다. 실제로는 DB connection, 외부 API client, queue, worker, tenant quota도 격리 대상이다.
- 핵심은 어떤 리소스가 공유되어 장애가 전파되는지 먼저 찾는 것이다.
확인 질문
- 확인 질문: Circuit Breaker와 Bulkhead가 바꾸는 설계 축은 무엇인가?
- 답변: 장애 격리는 개선하지만 fallback 품질, pool sizing, 상태 관측, 운영 설정이라는 복잡도를 늘린다.
- 확인 질문: 느린 외부 API가 로그인 API까지 느리게 만들 수 있는 이유는 무엇인가?
- 답변: 같은 서버 스레드, connection pool, worker queue를 공유하면 느린 호출이 공통 리소스를 점유해 정상 기능도 대기하게 되기 때문이다.
- 확인 질문: Fallback을 설계할 때 가장 먼저 정해야 하는 것은 무엇인가?
- 답변: 사용자가 어떤 축소 상태를 봐도 되는지, 어떤 데이터는 절대 대체하면 안 되는지 정해야 한다.