본문으로 바로가기

34

서킷 브레이커

이미 죽은 곳을 계속 두드리면 그쪽도 못 살아나고 이쪽까지 죽는다

먼저 보면 좋은 강의: 장애 조치(페일오버)

단계별로 보기

스페이스바로 재생/정지, 좌우 화살표로 단계 이동, R로 처음으로 돌아갑니다.

대기 중1 / 4 단계 — CLOSED — 평상시

차단기가 닫혀 있습니다. 회로가 닫혀 있어야 전기가 흐르듯, 닫힘이 정상 상태입니다. 요청이 그대로 통과합니다. 차단기는 아무것도 막지 않고 조용히 실패 횟수만 세고 있습니다. 평상시에 차단기는 있는지도 모르게 있어야 합니다.

이 강의를 마치면

  • 고장난 하류를 계속 호출하는 것이 왜 상황을 악화시키는지 설명한다.
  • CLOSED·OPEN·HALF_OPEN 세 상태와 그 사이를 오가는 조건을 설명한다.
  • 차단과 대체 응답이 각각 무엇을 해결하는지 구분한다.
  • 장애가 번지는 시스템에 차단기를 넣어 사용자를 지켜낸다.

죽은 문을 계속 두드리면

주문 서버가 저장소를 호출합니다. 저장소가 죽었습니다. 무슨 일이 벌어질까요?

"그냥 실패하겠지"라고 생각하기 쉽습니다. 그런데 훨씬 나쁩니다.

죽은 서버는 거절하지 않습니다. 아무 대답도 하지 않습니다. 그래서 주문 서버는 기다립니다. 30초짜리 타임아웃이 걸려 있다면 30초를 기다립니다.

그동안 그 요청을 처리하던 자리(스레드, 연결)는 묶여 있습니다. 다음 요청이 옵니다. 또 저장소를 부릅니다. 또 30초 묶입니다.

1초에 100건이 들어오고, 각각 30초씩 묶인다
  → 30초 뒤에는 3,000개의 자리가 전부 묶여 있다
  → 주문 서버에 남은 자리가 없다
  → 주문 서버도 죽는다

저장소 하나가 죽었는데 주문 서버까지 죽었습니다. 그리고 주문 서버를 부르던 다른 서비스도 같은 방식으로 죽습니다. 고장이 번집니다.

이것을 연쇄 장애라고 합니다. 작은 부품 하나의 고장이 전체를 삼키는 방식입니다. 대형 장애의 사후 보고서 대부분이 이 이야기입니다.

게다가 저쪽도 못 살아난다

저장소는 지금 되살아나려 하고 있습니다. 그런데 초당 100건의 요청이 계속 두드립니다. 겨우 일어서려는 순간 다시 쓰러집니다.

계속 두드리는 것이 회복을 막습니다. 도와주려던 게 아니라 방해한 것입니다.

두꺼비집을 단다

집 안 배선이 합선되면 두꺼비집이 스스로 내려갑니다. 그 방의 전기는 못 씁니다. 불편합니다. 하지만 집이 타지 않습니다.

서킷 브레이커는 이것을 그대로 옮긴 것입니다. 고장을 감지하면 아예 부르지 않습니다.

부르지 않으면 뭘 하냐고요? 즉시 실패하거나, 미리 준비한 답을 줍니다. 30초를 기다리지 않습니다. 자리가 묶이지 않습니다. 주문 서버가 삽니다.

세 가지 상태

차단기는 세 상태를 오갑니다.

     ┌──────────── 정상 ────────────┐
     │                              │
  CLOSED ──실패가 쌓이면──> OPEN ──잠시 뒤──> HALF_OPEN
     ↑                                            │
     └────────── 탐침 성공 ───────────────────────┘
                                                  │
     OPEN <────────── 탐침 실패 ──────────────────┘

CLOSED (닫힘 = 평상시) 전기가 흐르듯 요청이 그대로 통과합니다. 차단기는 조용히 실패 횟수만 셉니다. 헷갈리기 쉬운 이름입니다. "닫힘"이 정상입니다. 회로가 닫혀 있어야 전기가 흐르니까요.

OPEN (열림 = 차단 중) 실패가 기준을 넘으면 회로를 끊습니다. 이제 하류를 아예 부르지 않습니다. 요청이 오면 즉시 답합니다. 하류는 두들겨 맞지 않고 회복할 시간을 얻습니다. 호출하는 쪽은 자리가 묶이지 않습니다. 양쪽 다 삽니다.

HALF_OPEN (반쯤 열림 = 간 보는 중) 영원히 차단할 수는 없습니다. 잠시 뒤 딱 한 건만 시험 삼아 보내봅니다.

  • 성공하면 → 살아났구나 → CLOSED로 복귀
  • 실패하면 → 아직이구나 → 다시 OPEN

이 상태가 중요한 이유가 있습니다. 이게 없으면, 회복됐는지 확인하려고 막았던 트래픽을 한꺼번에 풀게 됩니다. 그러면 갓 일어선 서버가 그 순간 다시 쓰러집니다. 한 건씩 간을 보는 것이 핵심입니다.

차단만으로는 부족하다

차단기가 회로를 끊었습니다. 이제 요청이 오면 뭐라고 답할까요?

그냥 오류를 주면 사용자는 여전히 오류 화면을 봅니다. 서버는 살렸지만 사용자 경험은 그대로입니다. 여기서 한 걸음 더 갈 수 있습니다.

대체 응답(fallback) 입니다. 완벽하지 않아도 뭐라도 주는 것입니다.

원래 주려던 것대체 응답
개인 맞춤 추천 상품이번 주 인기 상품 (모두 같은 목록)
실시간 재고 수량"재고 확인 중입니다"
최신 프로필 사진조금 오래된 캐시 사진

사용자는 조금 아쉬운 화면을 봅니다. 오류 화면보다는 훨씬 낫습니다. 그리고 대부분 눈치채지 못합니다.

차단은 시스템을 살리고, 대체 응답은 사용자를 살립니다. 둘은 다른 일이고 둘 다 필요합니다.

대가

정직하게 말하면, 차단기는 멀쩡한 요청도 막습니다. OPEN인 동안에는 하류가 방금 살아났어도 부르지 않습니다. 그래서 실제보다 조금 더 오래 기능이 죽어 있습니다.

기준을 너무 민감하게 잡으면(2번 실패에 차단) 잠깐의 딸꾹질에도 기능이 꺼집니다. 너무 둔하게 잡으면(100번 실패에 차단) 이미 연쇄 장애가 시작된 뒤에 끊깁니다. 이 숫자는 하류의 성격을 보고 정해야 하며, 공짜 정답은 없습니다.

직접 해보세요

아래 과제는 10초 시점에 저장소가 죽습니다. 지금은 그 순간부터 사용자가 오류를 봅니다. 차단기를 넣어 사용자를 지켜내세요.

이 강의가 단순화한 것

교육용 모형은 언제나 무언가를 생략합니다. 무엇을 생략했는지 아는 것도 학습의 일부입니다.

전제한 것

  • 이 시뮬레이터의 죽은 노드는 즉시 오류를 돌려준다. 그래서 본문에서 설명한 '타임아웃까지 자리가 묶이는' 현상은 실행 화면에 그대로 나타나지 않는다. 실제 시스템에서 연쇄 장애를 만드는 주범은 이 대기 시간이며, 차단기의 존재 이유이기도 하다.
  • 대체 응답은 하류를 부르지 않고 즉시 만들 수 있다고 본다. 실제로는 대체 응답을 만들 재료(캐시 등)를 미리 준비해 둬야 하며, 그것도 공짜가 아니다.
  • 차단기의 상태는 이 서버 안에만 있다고 본다. 서버가 여러 대면 각자 따로 세므로, 전체가 동시에 차단되지는 않는다.
  • 실패 임계값·리셋 시간 같은 숫자는 이 과제를 위해 고른 값이며 보편적인 권장값이 아니다.

다루지 않은 것

  • 타임아웃과 벌크헤드(자원 격리) — 차단기와 함께 써야 효과가 있다
  • 여러 서버가 차단 상태를 공유하는 방법
  • 부분 차단(요청 종류별로 다르게 판단)
  • 차단기와 재시도를 함께 쓸 때의 상호작용

더 읽을거리: Martin Fowler — CircuitBreaker · Google SRE Book — Addressing Cascading Failures

이제 직접 만들어 보세요

읽어서 아는 것과 만들어서 아는 것은 다릅니다. 컴포넌트를 배치하고 트래픽을 흘려서 실제로 동작하는지 확인해 보세요.

실습 과제 열기

이 강의에 물어보기

하루 5번

이 강의 본문만 근거로 답합니다. 강의에 없는 내용은 지어내지 않습니다.