Implementing a Circuit Breaker and Verifying Its Transitions
한국어 원문으로 표시합니다.
목표
서킷 브레이커를 직접 구현해 CLOSED, OPEN, HALF_OPEN 사이의 전이를 눈으로 확인하고, 무엇을 실패로 셀지의 결정이 왜 가장 중요한지 사고 사례로 체감한다.
왜 중요한가
서킷 브레이커는 장애를 고치는 장치가 아닙니다. 장애가 확실할 때 빠르게 실패해서 호출자의 커넥션 풀이 마르지 않게 지키는 장치입니다. 그래서 성능 지표가 아니라 격리 지표로 평가해야 합니다. 실무에서 서킷이 만드는 사고는 대부분 두 가지입니다. 첫째, 4xx 를 실패로 집계해 정상 트래픽까지 차단하는 것 — 재고 서비스가 특정 상품에 400 을 주기 시작하자 서킷이 열려 정상 상품 조회까지 막힌 사례가 있습니다. 둘째, HALF_OPEN 시험 호출을 1건만 허용해 OPEN 과 HALF_OPEN 을 오가며 플래핑하는 것입니다. 이 실습은 그 두 함정을 각각 한 스텝씩 배정해 직접 만들고 직접 막습니다.
단계
/opt/app/flaky.py를 127.0.0.1:8110 에 띄운다.GET /count가 지금까지 받은 요청 수를 JSON 으로 준다./root/cb/breaker.py를 만들어/fast를 3번 호출한다./root/cb/state.json에{"state":"CLOSED", ...}를 쓴다./always500을 5번 호출해 실패율 임계값을 넘긴다. 설정은 윈도우 10, 최소 호출 5, 실패율 50% 이다.state.json의state가OPEN이 된다.- OPEN 상태에서 10번 더 호출한다.
/root/cb/fastfail.txt에before=<n> after=<n> blocked=10 max_ms=<밀리초>를 적는다. before 와 after 가 같아야 하고 max_ms 는 50 미만이어야 한다. waitDurationInOpenState를 3초로 두고 3초 이상 기다린 뒤 한 번 호출한다.state.json의state가HALF_OPEN이 된다.- HALF_OPEN 에서
/fast를 3번 성공시켜CLOSED로 되돌린다.permitted_in_half_open값이 3 이상으로 기록되어야 한다. - 새 브레이커로
/bad(400)를 10번 호출한다./root/cb/ignore4xx.json의state는 여전히CLOSED이고failures는 0 이어야 한다. - 전체 시나리오를 한 번에 돌려
/root/cb/transitions.log에CLOSED->OPEN,OPEN->HALF_OPEN,HALF_OPEN->CLOSED세 줄을 이 순서로 남긴다.
참고
- 출발점 설정: 윈도우 10, 최소 호출 5, 실패율 50%, 느린 호출 3초, OPEN 대기 30초(실습은 3초), HALF_OPEN 시험 3건
- 서비스별 임계값: 결제 30–40%, 알림 60–70%
- 흔한 실수 1:
minimumNumberOfCalls를 채우기 전에 판정해 호출 1건 실패로 서킷이 열리는 것. - 흔한 실수 2: 폴백을
return None으로 두는 것 — 서킷이 장애를 다른 예외로 바꾼 것에 불과합니다.
다운스트림과 호출 카운터 준비하기
/opt/app/flaky.py 를 127.0.0.1:8110 에 띄운다. GET /count 가 지금까지 받은 요청 수를 JSON 으로 준다.
/opt/app/flaky.py 는 자기가 받은 요청 수를 /count 로 알려줍니다. 이 값이 뒤 스텝에서 증거가 됩니다.
CLOSED 상태에서 통과시키기
/root/cb/breaker.py 를 만들어 /fast 를 3번 호출한다. /root/cb/state.json 에 {"state":"CLOSED", ...} 를 쓴다.
상태를 파일에 남겨야 채점할 수 있습니다. 상태 이름, 실패 수, 윈도우 크기를 JSON 으로 적으세요.
실패율 임계값으로 OPEN 만들기
/always500 을 5번 호출해 실패율 임계값을 넘긴다. 설정은 윈도우 10, 최소 호출 5, 실패율 50% 이다. state.json 의 state 가 OPEN 이 된다.
최소 호출 수를 채우기 전에는 판정하지 않습니다. 윈도우 10, 최소 5, 임계 50% 를 그대로 구현하세요.
OPEN 에서 다운스트림에 가지 않음을 증명하기
OPEN 상태에서 10번 더 호출한다. /root/cb/fastfail.txt 에 before=<n> after=<n> blocked=10 max_ms=<밀리초> 를 적는다. before 와 after 가 같아야 하고 max_ms 는 50 미만이어야 한다.
차단 전후로 다운스트림의 호출 카운터가 그대로여야 합니다. 그리고 응답이 아주 빨라야 합니다.
대기 시간 후 HALF_OPEN 으로 전이하기
waitDurationInOpenState 를 3초로 두고 3초 이상 기다린 뒤 한 번 호출한다. state.json 의 state 가 HALF_OPEN 이 된다.
OPEN 진입 시각을 기록해 두고 경과를 비교합니다. 자동 전이가 되어야 사람이 개입하지 않습니다.
시험 호출 성공으로 CLOSED 복귀하기
HALF_OPEN 에서 /fast 를 3번 성공시켜 CLOSED 로 되돌린다. permitted_in_half_open 값이 3 이상으로 기록되어야 한다.
시험 호출 수를 1 로 두면 플래핑이 생깁니다. 왜 3 이상이어야 하는지 생각하면서 구현하세요.
4xx 를 실패로 세지 않기
새 브레이커로 /bad(400)를 10번 호출한다. /root/cb/ignore4xx.json 의 state 는 여전히 CLOSED 이고 failures 는 0 이어야 한다.
400 은 클라이언트 잘못이므로 서킷이 개입할 일이 아닙니다. 무엇을 실패로 볼지 목록으로 관리하세요.
전이 이력으로 종합 검증하기
전체 시나리오를 한 번에 돌려 /root/cb/transitions.log 에 CLOSED->OPEN, OPEN->HALF_OPEN, HALF_OPEN->CLOSED 세 줄을 이 순서로 남긴다.
앞 스텝들을 한 시나리오로 이어 붙여 네 가지 상태 전이가 순서대로 기록되게 만드세요.