> For the complete documentation index, see [llms.txt](https://leehyokyun.gitbook.io/openbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://leehyokyun.gitbook.io/openbook/5-5.-circuit-breaker-and-fallback.md).

# 5-5. 분산 시스템의 내결함성, 회복 탄력성 (Circuit Breaker & Fallback)

분산 시스템의 내결함성 및 회복탄력성에 대하여

### Fallback에 대하여

* 개념 및 구조적 예시 어떤 기능이 실패했을 때 대신 수행되는 대체 로직을 의미한다. 이는 단순한 대체 로직이 아니라 서비스 안정성을 향상시킬 수 있는 중요한 장치이다.
* 네트워크: Primary DNS 실패 시 Secondary DNS로 대체 수행한다.
* 데이터베이스: Primary DB 장애 시 Replica DB로 대체 작동한다.
* CDN: CDN cache miss 발생 시 Origin Server로 요청을 전달한다.
* UI: 이미지 로딩 실패 시 와 같이 기본 이미지로 대체한다.
* 적용 예시 및 방식 상품 서비스 호출 성공 시 주문 정보를 반환하고, 실패 시 fallback을 실행하여 빈 리스트나 캐시 데이터, 혹은 에러 메시지를 반환한다. 대체 로직뿐만 아니라 기존의 데이터로 대체하는 Request Collapsing 방식이 존재하며, 나아가 Semaphore를 통해 일정 수준 이상의 트래픽은 모두 fail 처리하는 fail fast 방식이 존재한다.

### Circuit Breaker vs Fallback

* 개념과 차이점 Fallback이 실패 시 대체되는 로직이라면, Circuit Breaker는 실패 시 서비스를 차단하고 우회하는 시스템이다. 서비스 호출 실패 시 오류가 전파되는 것을 방지하기 위해 차단 혹은 우회(fallback 유도)를 수행한다. 정상 확인 상태라면 Closed(회로 폐쇄) 상태로 유지되다가, 실패가 증가하면 오류 전염을 막기 위해 Open(차단) 상태로 전환된다.
* 장애 전파 비교
* Circuit Breaker가 없을 때: Order Service가 장애 상태인 Payment Service를 호출하면 Timeout이 발생하고 스레드 풀이 고갈된다. 분산 트랜잭션 구조상 Order Service까지 연쇄적으로 장애가 전파되어 전체 시스템 장애로 이어진다.
* Circuit Breaker가 있을 때: Payment Service 장애가 지속되면 실패율과 timeout 기준을 초과하여 회로가 OPEN 상태로 바뀐다. 이후에는 Order Service가 Payment Service를 아예 호출하지 않고 빠르게 실패를 반환하여 시스템을 보호한다. 전기 차단기와 같이 전류가 과도하게 흐르거나 고장난 서비스에 요청이 몰리면 호출을 차단하는 원리이다.
* 생명 주기 및 연동 특정 호출 표본을 통해 상태를 관리한다. 일정 시간이 지나면 HALF-OPEN 상태로 진입하여 테스트 요청을 몇 개만 보내고, 성공하면 다시 CLOSED로 돌아가고 실패하면 OPEN 상태를 유지한다. 회로가 Open되어 호출을 막았을 때 대체 응답을 주기 위해 보통 Fallback을 함께 조합하여 사용한다. 이러한 도구를 제공하는 라이브러리가 Resilience4j이다.

### Semaphore vs Circuit Breaker

* 동작 방식의 차이
* Semaphore: Pre-Eventive(예방적) 방식으로, 자원 자체를 격리하고 최대 허용치를 정하여 Thread의 불필요한 소모를 방지한다. 전체 스레드가 100개일 때 A 서비스에 30개, B 서비스에 30개, C 서비스에 40개와 같이 자원을 사전에 배분한다.
* Circuit Breaker: Reactive(반응적) 방식으로, 일단 진행하고 실패율이 누적되면 그때 서비스 호출을 차단한다. 스레드 풀을 격리하는 것이 아니라 전역적으로 관리하며, 실패 누적에 따른 불필요한 소모를 차단한다.

### Bulkhead의 두 가지 실행 모델 (Semaphore vs ThreadPool)

* 리소스 격리 규칙 Bulkhead 패턴을 통해 동시에 실행하는 처리량 및 최대 호출 개수의 상한을 지정하여 리소스를 격리(Isolation)한다. 실패율 개념이 존재하지 않으며 제한을 넘으면 즉시 거절한다.
* Semaphore 기반 Bulkhead: Permit이라는 내부 카운터를 기반으로 동시 실행 요청 수를 제한한다. 최대 제한(예: 10개)까지 실행 중일 때 11번째 요청이 들어오면 즉시 거절한다. 별도의 스레드 풀을 관리하지 않으므로 오버헤드가 적고 단순한 동시성 제어에 유용하다.
* ThreadPool 기반 Bulkhead: 사용 가능한 전용 ThreadPool을 기준으로 실행한다. Pool에 여유가 있으면 바로 실행되고, 스레드가 모두 사용 중이라면 요청이 대기 큐에 쌓여 스레드가 사용 가능해질 때까지 대기한다. 작업 시간이 길고 완전한 리소스 격리가 필요한 외부 API 호출 등의 환경에서 효율적이지만, 결과를 얻을 때까지 해당 스레드가 Blocking되는 특성이 있다.

### webMVC 및 webClient의 구조적 차이와 TimeLimiter 관련 동작

* TimeLimiter 패턴의 원리 TimeLimiter는 기본적으로 비동기/Blocking 기반으로 Thread 호출 시 Future의 완료 시간을 제한하는 패턴이다. 비동기 작업을 시작하면 Future 또는 Mono를 반환하고 timeout scheduler를 등록한다. 그렇기에 TimeLimiter는 반드시 비동기(Async) 기반의 작업이 필요하며 반환 타입도 Future 형태여야 한다. timeout이 초과되면 Future cancel 또는 Mono timeout을 유도한다.
* webMVC 환경의 문제점: HTTP 통신에서 Thread는 동기이자 Blocking 방식으로 작동하므로 Timeout(Time Interrupt) 작용이 불가하다. 이미 스레드가 block되어 응답이 올 때까지 대기하므로, TimeLimiter가 작동 불가하여 리소스 낭비가 발생하고 Future 스레드를 추가 사용하게 된다.
* webFlux 환경: Reactive 기반의 webFlux 환경에서는 Thread가 비동기/Non-Blocking 방식으로 작동한다. 결과가 도착했을 때 반응하는 구조이므로 Timer가 제대로 동작할 수 있는 환경이 조성되어 Resilience4j 패턴이 안정적으로 적용된다.

### 비동기와 Blocking 실행 모델의 채택 이유

* 혼합 모델의 존재 이유와 효율성 비동기 + Blocking 조합이 결국 동기와 같은 결과가 아닌가 하는 의문이 있을 수 있으나, 이는 비동기 환경을 보호하기 위한 조치이다. `CompletableFuture.supplyAsync(() -> api.call())` 사용 시 Thread A가 비동기 작업을 요청하면 바로 리턴을 받지만, 백그라운드의 Thread B(worker)는 API 호출 결과를 받을 때까지 BLOCK 상태로 동기식 대기를 수행한다. 비동기 방식의 스레드를 먼저 호출하여 스레드들이 병렬로 처리하지만, 전체 결과에 대한 동기화를 위해 대기(Blocking)하며 결과를 합산하는 구조가 필요하다. Kafka와 같은 외부 통신 환경에서도 메인 스레드 풀을 보호하면서 워커 스레드가 결과를 대기하는 방식이 활용된다. 반면 WebFlux는 내부 환경 자체가 비동기와 Non-Blocking으로 이루어져 있으며, Event Queue를 통한 이벤트 기반 처리를 활용하여 Event Loop와 함께 요청을 가장 빠르고 효율적으로 처리해 낸다.

### DTO와 Entity를 분리하는 이유

* 도메인 보호와 결합도 분리 가장 결정적인 이유는 내부 도메인 요소 및 비즈니스 규칙 등을 외부에 노출하지 않기 위함이다. 외부 계층에서는 내부적인 스키마 변경에 의존(관심)하지 않고, 계약(Contract)에 기반한 일관된 구조로 접근이 가능하다. 내부적인 요소와 외부 접근 경로(계약/인터페이스)를 분리하여 두 경로에 대해 독립성과 일관성을 안정적으로 유지할 수 있다.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://leehyokyun.gitbook.io/openbook/5-5.-circuit-breaker-and-fallback.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
