What is Circuit Breaker?
Circuite breaker는 애플리케이션 또는 서버단에서 장애가 발생했을 때 그 장애가 다른 서비스로 전파되는 것을 방지하기 위한 기술이다. 예를 들면 A 서비스가 B 서비스에 요청을 보낼 때 B 서비스에서 문제가 발생하면 A 서비스 또한 응답을 리턴을 못해주므로 영향이 가게된다. 이러한 상황을 Circuit breaker로 방지할 수 있다.
Circuit Breaker의 상태
- CLOSED: 정상적으로 호출이 이루어지느 상태
- OPEN: 장애가 발생하여 호출이 차단된 상태
- HALF OPEN: 일정 시간이 지난 후 다시 호출을 시도하는 상태
[Configuration] 애플리케이션 준비
우선 실습을 위한 개발한 Python 애플리케이션 두 개를 생성 후 Docker Hub 또는 AWS ECR과 같은 Registry에 Push 후 진행.
각 애플리케이션은 service a의 /call-service-b로 호출 시 service_b.py에 호출이 되게끔 설계 했으며, 이때 service b는 30% 확률로 500 오류를 반환한다.
# service_a.py
from flask import Flask, jsonify
import requests
app = Flask(__name__)
@app.route('/call-service-b')
def call_service_b():
try:
response = requests.get('http://service-b:5001/api', timeout=2)
response.raise_for_status()
return jsonify(response.json()), response.status_code
except requests.exceptions.RequestException as e:
return jsonify({"error": "Service B failed", "details": str(e)}), 503
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
# service_b.py
from flask import Flask, jsonify
import random
app = Flask(__name__)
@app.route('/api')
def unstable_endpoint():
if random.random() < 0.3: # 30% 확률로 에러 발생
return jsonify({"message": "Error occurred!"}), 500
return jsonify({"message": "Success!"}), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5001)
※ 그 후 deployment 생성 후 istio로 mesh 서비스 환경을 구축
[Configuration] Circuit Breaker를 적용하기
우선 Circuit Breaker를 적용하기 전에 kiali와 curl을 통해 간단하게 테스트 해보자.
위와 같이 10번 시도하였을 때 3번 정로다 오류가 발생한 것을 알 수 있다.
이를 해결하기 위해 Circuit Breaker를 사용하여 만약 요청을 한 Pod에서 500을 반환했을 때 Fallback 메커니즘을 사용하여 다른 Pod에서 이를 처리하고 사용자에게 정상 패킷을 반환할 수 있도록 설정해보자.
# destination-rule-service-b.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: service-b-circuit-breaker
namespace: circuit
spec:
host: service-b
trafficPolicy:
outlierDetection:
consecutive5xxErrors: 2 # 5xx 오류가 2회 연속 발생하면 Circuit Breaker 발동
interval: 5s # 오류를 체크하는 주기
baseEjectionTime: 30s # Circuit Breaker 발동 시 30초간 해당 서비스로의 트래픽을 차단
maxEjectionPercent: 100 # 서비스 전체를 차단
위와 같은 Destination Rule Manifest를 작성 후 적용해본 뒤 테스트를 해보자. 그 후 API를 테스트 해보면 아래와 같이 오류가 많이 뜨는 것을 볼 수 있다.
이는 DestinationRule 옵션에서 spec.trafficPolicy에 옵션에 의해 5xx 오류가 5초 동안 2번 발생할 경우 30초 동안 해당 서비스로의 트래픽을 전체 차단하도록 설정이되어있는데, 우리의 애플리케이션은 50% 확률로 500오류를 반환하여 circuit breaker가 계속 OPEN 상태를 유지하고 있으므로 Service Unavailable 오류가 발생하는 것이다.
이를 해결하기 위해선 outlierDetection.baseEjectionTime과 outlierDetection.interval의 시간을 줄어봐야한다.
# destination-rule-service-b.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: service-b-circuit-breaker
namespace: circuit
spec:
host: service-b
trafficPolicy:
outlierDetection:
consecutive5xxErrors: 1
interval: 1s
baseEjectionTime: 1s
maxEjectionPercent: 100
그 후 테스트를 해보자. 아래와 같이 로그 상에선 200과 500이 확률적으로 반환되었으나, Circuit Breaker를 통해서 실제 사용자에겐 정상 적응 응답이 반환 된 것을 알 수 있다.
이를 통해 interval, baseejectionTIme 옵션에 대해 설정 값을 바꿈으로 써 애플리케이션의 장애 률이 달라지는 것을 볼 수 있다.
'Containers > Kubernetes' 카테고리의 다른 글
[Kubernetes] Graceful하게 애플리케이션 운영하기 (Graceful Shutdown) (0) | 2024.11.01 |
---|
댓글