

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 회로 차단기 패턴
<a name="circuit-breaker"></a>

## 의도
<a name="circuit-breaker-intent"></a>

회로 차단기 패턴은 직접 호출이 이전에 반복된 제한 시간 초과 또는 장애의 원인인 경우 직접 호출자 서비스가 다른 서비스(*피호출자*)에 대한 직접 호출을 재시도하지 못하게 할 수 있습니다. 이 패턴은 수신자 서비스가 다시 작동하는 시점을 감지하는 데도 사용됩니다.

## 목적
<a name="circuit-breaker-motivation"></a>

요청을 처리하기 위해 여러 마이크로서비스가 협업하는 경우 하나 이상의 서비스를 사용할 수 없게 되거나 지연 시간이 길어질 수 있습니다. 복잡한 애플리케이션에서 마이크로서비스를 사용하는 경우 한 마이크로서비스의 중단으로 인해 애플리케이션 장애가 발생할 수 있습니다. 마이크로서비스는 원격 프로시저 직접 호출을 통해 통신하며, 네트워크 연결에서 일시적인 오류가 발생하여 장애가 발생할 수 있습니다. (일시적인 오류는 [백오프 패턴으로 재시도](retry-backoff.md)를 사용하여 처리할 수 있습니다.) 동기식 실행 중에 제한 시간 초과 또는 장애가 계단식으로 발생하면 사용자 경험이 저하될 수 있습니다.

그러나 일부 상황에서는 피호출자 서비스가 중단되거나 데이터베이스 경합으로 인해 제한 시간이 초과되는 경우와 같이 장애 해결 시간이 더 오래 걸릴 수 있습니다. 이러한 경우 직접 호출 서비스가 직접 호출을 반복적으로 재시도하면 이러한 재시도로 인해 네트워크 경합 및 데이터베이스 스레드 풀 소비가 발생할 수 있습니다. 또한 여러 사용자가 애플리케이션을 반복적으로 재시도하면 문제가 악화되고 전체 애플리케이션에서 성능이 저하될 수 있습니다.

회로 차단기 패턴은 Michael Nygard의 저서 *Release It*(Nygard 2018)에서 인기를 얻었습니다. 이 설계 패턴은 직접 호출자 서비스가 이전에 반복된 제한 시간 초과 또는 장애의 원인이 되는 서비스 직접 호출을 재시도하지 못하게 할 수 있습니다. 또한 수신자 서비스가 다시 작동하는 시점을 감지할 수도 있습니다.

회로 차단기 객체는 회로에 이상이 있을 때 자동으로 전류를 차단하는 전기 회로 차단기와 같이 작동합니다. 장애가 발생할 때 전기 회로 차단기는 전류 흐름을 차단하거나 트립합니다. 마찬가지로 회로 차단기 객체는 직접 호출자와 피호출자 서비스 사이에 있으며 직접 호출자를 사용할 수 없는 경우 트립합니다.

[분산 컴퓨팅의 오류](https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing)는 Peter Deutsch와 Sun Microsystems의 다른 사람들이 만든 어설션 세트입니다. 분산 애플리케이션을 처음 사용하는 프로그래머는 항상 거짓 가정을 합니다. 네트워크 신뢰성, 제로 지연 시간에 대한 기대치 및 대역폭 제한 사항으로 인해 네트워크 오류에 대한 오류 처리를 최소화하면서 소프트웨어 애플리케이션이 작성됩니다.

네트워크 중단 중에 애플리케이션은 응답을 무기한으로 대기하고 애플리케이션 리소스를 계속 사용할 수 있습니다. 네트워크를 사용할 수 있게 되었을 때 작업을 재시도하지 않으면 애플리케이션 성능이 저하될 수도 있습니다. 네트워크 문제로 인해 데이터베이스 또는 외부 서비스에 대한 API 직접 호출의 제한 시간이 초과되는 경우 회로 차단기가 없는 반복된 직접 호출은 비용 및 성능에 영향을 줄 수 있습니다.

## 적용 가능성
<a name="circuit-breaker-applicability"></a>

다음과 같은 경우 이 패턴을 사용합니다.
+ 직접 호출자 서비스가 실패할 가능성이 가장 큰 직접 호출을 수행합니다.
+ 피호출자 서비스에서 나타나는 지연 시간이 길면(예: 데이터베이스 연결이 느린 경우) 직접 호출자 서비스에서 제한 시간 초과가 발생합니다.
+ 직접 호출자 서비스는 동기식 직접 호출을 수행하지만 피호출자 서비스가 사용 불가능하거나 해당 지연 시간이 높습니다.

## 문제 및 고려 사항
<a name="circuit-breaker-issues"></a>
+ **서비스에 구애받지 않는 구현:** 코드 팽창을 방지하려면 마이크로서비스에 구애받지 않고 API에 기반한 방식으로 회로 차단기 객체를 구현하는 것이 좋습니다.
+ **피호출자의 회로 폐쇄:** 피호출자가 성능 문제 또는 장애로부터 복구되면 회로 상태를 `CLOSED`로 업데이트할 수 있습니다. 회로 차단기 패턴의 확장 기능이며 목표 복구 시간(RTO)에 필요한 경우 구현할 수 있습니다.
+ **다중 스레드 직접 호출:** 만료 제한 시간 값은 서비스 가용성을 확인하기 위해 직접 호출이 다시 라우팅되기 전에 회로가 트립된 상태로 유지되는 기간으로 정의됩니다. 피호출자 서비스가 여러 스레드에서 직접 호출되면 실패한 첫 번째 직접 호출이 만료 제한 시간 값을 정의합니다. 구현을 통해 후속 직접 호출이 만료 제한 시간을 영구적으로 이전하지 않도록 해야 합니다.
+ **회로 강제 열기 또는 닫기:** 시스템 관리자는 회로를 열거나 닫을 수 있어야 합니다. 데이터베이스 테이블의 만료 제한 시간 값을 업데이트하여 이 작업을 수행할 수 있습니다.
+ **관찰성:** 회로 차단기가 열려 있을 때 실패하는 직접 호출을 식별하기 위해 애플리케이션에 로깅이 설정되어 있어야 합니다.

## 구현
<a name="circuit-breaker-implementation"></a>

### 전반적인 아키텍처
<a name="circuit-high-level-arch"></a>

다음 예제에서 직접 호출자는 주문 서비스이고 피호출자는 결제 서비스입니다.

장애가 없는 경우 주문 서비스는 다음 다이어그램과 같이 회로 차단기를 통해 모든 직접 호출을 결제 서비스로 라우팅합니다.

![장애가 없는 회로 차단기 패턴.](http://docs.aws.amazon.com/ko_kr/prescriptive-guidance/latest/cloud-design-patterns/images/circuit-breaker-1.png)


결제 서비스가 시간 초과되면 회로 차단기가 시간 초과를 감지하고 장애를 추적할 수 있습니다.

![결제 서비스 장애가 있는 회로 차단기.](http://docs.aws.amazon.com/ko_kr/prescriptive-guidance/latest/cloud-design-patterns/images/circuit-breaker-2.png)


제한 시간이 지정된 임계치를 초과하면 애플리케이션이 회로를 엽니다. 회로가 열려 있으면 회로 차단기 객체가 직접 호출을 결제 서비스로 라우팅하지 않습니다. 주문 서비스가 결제 서비스를 직접 호출하면 즉각적인 실패를 반환합니다.

![회로 차단기가 결제 서비스로의 라우팅을 중지합니다.](http://docs.aws.amazon.com/ko_kr/prescriptive-guidance/latest/cloud-design-patterns/images/circuit-breaker-3.png)


회로 차단기 객체가 결제 서비스에 대한 직접 호출이 성공했는지 주기적으로 확인합니다.

![회로 차단기가 결제 서비스를 주기적으로 재시도합니다.](http://docs.aws.amazon.com/ko_kr/prescriptive-guidance/latest/cloud-design-patterns/images/circuit-breaker-4.png)


결제 서비스에 대한 직접 호출이 성공하면 회로가 닫히고 모든 추가적인 직접 호출이 결제 서비스로 다시 라우팅됩니다.

![결제 서비스가 작동하는 회로 차단기.](http://docs.aws.amazon.com/ko_kr/prescriptive-guidance/latest/cloud-design-patterns/images/circuit-breaker-5.png)


### AWS 서비스를 사용한 구현
<a name="circuit-aws-services"></a>

샘플 솔루션에서는 [AWS Step Functions](https://aws.amazon.com/step-functions/)에서 Express 워크플로를 사용하여 회로 차단기 패턴을 구현합니다. Step Functions 상태 머신에서는 패턴 구현에 필요한 재시도 기능 및 의사 결정 기반 제어 흐름 요구 사항을 구성할 수 있습니다.

또한 솔루션은 [Amazon DynamoDB](https://aws.amazon.com/dynamodb/) 테이블을 데이터 저장소로 사용하여 회로 상태를 추적합니다. 더 나은 성능을 위해 [Amazon ElastiCache(Redis OSS)](https://aws.amazon.com/elasticache/redis/)와 같은 인 메모리 데이터 저장소로 교체할 수 있습니다.

서비스가 다른 서비스를 직접 호출하려는 경우 피호출자 서비스의 이름으로 워크플로를 시작합니다. 워크플로는 현재 성능이 저하된 서비스를 저장하는 DynamoDB `CircuitStatus` 테이블에서 회로 차단기 상태를 가져옵니다. `CircuitStatus`에 피호출자에 대해 만료되지 않은 레코드가 포함된 경우 회로가 열립니다. Step Functions 워크플로는 즉각적인 실패를 반환하고 `FAIL` 상태로 종료됩니다.

`CircuitStatus` 테이블에 피호출자에 대한 레코드가 없거나 만료된 레코드가 포함된 경우 서비스는 작동 가능합니다. 상태 시스템 정의의 `ExecuteLambda` 단계에서는 파라미터 값을 통해 전송되는 Lambda 함수를 직접 호출합니다. 직접 호출이 성공하면 Step Functions 워크플로가 `SUCCESS` 상태로 종료됩니다.

![AWS Step Functions 및 DynamoDB를 사용한 회로 차단기 구현.](http://docs.aws.amazon.com/ko_kr/prescriptive-guidance/latest/cloud-design-patterns/images/circuit-breaker-6.png)


서비스 직접 호출이 실패하거나 제한 시간이 초과되면 애플리케이션은 정의된 횟수만큼 지수 백오프를 사용하여 재시도합니다. 재시도 후 서비스 직접 호출이 실패하면 워크플로는 `ExpiryTimeStamp`를 사용하여 서비스에 대한 `CircuitStatus` 테이블에 레코드를 삽입하고 워크플로는 `FAIL` 상태로 종료됩니다. 동일한 서비스에 대한 후속 직접 호출은 회로 차단기가 열려 있는 한 즉각적인 장애를 반환합니다. 상태 시스템 정의의 `Get Circuit Status` 단계에서는 `ExpiryTimeStamp` 값을 기반으로 서비스 가용성을 확인합니다. 만료된 항목은 DynamoDB Time To Live(TTL) 기능을 사용하여 `CircuitStatus` 테이블에서 삭제됩니다.

### 샘플 코드
<a name="circuit-sample-code"></a>

다음 코드에서는 `GetCircuitStatus` Lambda 함수를 사용하여 회로 차단기 상태를 확인합니다.

```
var serviceDetails = _dbContext.QueryAsync<CircuitBreaker>(serviceName, QueryOperator.GreaterThan,
                new List<object>
                    {currentTimeStamp}).GetRemainingAsync();

if (serviceDetails.Result.Count > 0)
{
    functionData.CircuitStatus = serviceDetails.Result[0].CircuitStatus;
}
else
{
    functionData.CircuitStatus = "";
}
```

다음 코드에서는 Step Functions 워크플로의 Amazon States Language 문을 보여줍니다.

```
"Is Circuit Closed": {
    "Type": "Choice",
    "Choices": [
    {
        "Variable": "$.CircuitStatus",
        "StringEquals": "OPEN",
        "Next": "Circuit Open"
    },
    {
        "Variable": "$.CircuitStatus",
        "StringEquals": "",
        "Next": "Execute Lambda"
    }
    ]
},
"Circuit Open": {
    "Type": "Fail"
}
```

### GitHub 리포지토리
<a name="circuit-breaker-github-repo"></a>

이 패턴에 대한 샘플 아키텍처의 전체 구현은 [https://github.com/aws-samples/circuit-breaker-netcore-blog](https://github.com/aws-samples/circuit-breaker-netcore-blog) GitHub 리포지토리를 참조하세요.

## 블로그 참조
<a name="circuit-breaker-blog"></a>
+ [AWS Step Functions 및 Amazon DynamoDB에서 회로 차단기 패턴 사용](https://aws.amazon.com/blogs/compute/using-the-circuit-breaker-pattern-with-aws-step-functions-and-amazon-dynamodb/)

## 관련 콘텐츠
<a name="circuit-breaker-resources"></a>
+ [Strangler Fig 패턴](strangler-fig.md)
+ [백오프 패턴으로 재시도](retry-backoff.md)