35강
재시도와 백오프
다시 해보는 것은 좋은 습관이지만, 모두가 동시에 다시 하면 그것이 공격이 된다
먼저 보면 좋은 강의: 서킷 브레이커
단계별로 보기
스페이스바로 재생/정지, 좌우 화살표로 단계 이동, R로 처음으로 돌아갑니다.
대기 중1 / 4 단계 — 잠깐의 실패에는 잘 듣는다
요청 하나가 이유 없이 실패했습니다. 패킷이 사라졌거나 연결이 잠깐 끊긴 것입니다. 다시 보내니 성공합니다. 이런 실패는 금방 지나가기 때문에 재시도가 거의 공짜로 가용성을 올려줍니다. 문제는 모든 실패가 이렇게 생기지는 않는다는 점입니다.
이 강의를 마치면
- 재시도가 해결하는 문제(일시적 실패)와 해결하지 못하는 문제(용량 부족)를 구분한다.
- 재시도가 부하를 증폭시켜 장애를 키우는 과정을 설명한다.
- 백오프와 지터가 각각 무엇을 고치는지 구분해 설명한다.
- 재시도 폭풍을 견디는 데 필요한 여유 용량을 직접 확보한다.
다시 해보면 대개 된다
네트워크는 가끔 이유 없이 실패합니다. 패킷 하나가 사라지고, 서버가 재시작 중이고, 연결이 잠깐 끊깁니다. 이런 실패는 금방 지나갑니다.
이럴 때 재시도는 거의 공짜로 가용성을 올려줍니다.
한 번에 성공할 확률 99%
→ 실패할 확률 1%
두 번 시도하면 둘 다 실패할 확률 = 0.01 × 0.01 = 0.01%
→ 가용성 99% → 99.99%코드 몇 줄로 정지 시간을 3.6일에서 1시간 아래로 줄였습니다. 그래서 재시도는 어디에나 들어갑니다. 문제는 바로 그것입니다.
언제 독이 되는가
위 계산에는 조용한 가정이 있습니다. 실패가 일시적이고, 서로 무관하다는 가정입니다.
서버가 용량이 부족해서 실패하고 있다면? 다시 해도 실패합니다. 용량이 부족한 건 그대로니까요. 그리고 재시도가 부하를 더합니다.
| 실패의 원인 | 재시도가 도움이 되나 |
|---|---|
| 패킷 유실, 순간적 끊김 | 예. 아주 잘 듣습니다 |
| 서버 재시작 중 | 예 |
| 용량 부족(과부하) | 아니오. 악화시킵니다 |
| 잘못된 요청(400) | 아니오. 백 번 해도 잘못된 요청입니다 |
아래 두 줄이 핵심입니다. 재시도는 상대가 일시적으로 못 받는 상황을 위한 것이지, 구조적으로 못 받는 상황을 위한 것이 아닙니다.
재시도 폭풍
과부하 상황에서 무슨 일이 벌어지는지 따라가 봅시다.
1. 서버가 과부하로 요청의 30%를 실패시킨다
2. 실패한 30%가 전부 재시도한다
3. 서버가 받는 부하 = 원래 100% + 재시도 30% = 130%
4. 더 과부하가 된다 → 실패가 50%로 는다
5. 실패한 50%가 재시도한다 → 부하 150%
6. 실패가 70%로 는다 → 부하 170%
...실패해서 재시도하고, 재시도해서 더 실패합니다. 스스로를 먹고 자랍니다.
가장 무서운 것은 이겁니다. 원래 원인이 사라져도 안 끝납니다. 트래픽이 정상으로 돌아와도 재시도가 만든 부하가 시스템을 계속 과부하로 묶어둡니다. 누군가 트래픽을 강제로 끊어 고리를 깨기 전까지 영원히 죽어 있습니다.
규칙 1 — 기다렸다가 한다 (백오프)
실패하자마자 곧바로 다시 하면, 그 순간 서버는 여전히 아픕니다. 그래서 기다립니다. 그리고 실패할수록 더 오래 기다립니다.
1차 실패 → 1초 기다림
2차 실패 → 2초 기다림
3차 실패 → 4초 기다림
4차 실패 → 8초 기다림 (실패할 때마다 두 배)이것이 지수 백오프입니다. 상대가 아플수록 덜 자주 찾아갑니다. 회복할 틈을 주는 것입니다. 앞 강의의 서킷 브레이커와 같은 정신입니다.
규칙 2 — 제각각 다른 시간에 한다 (지터)
백오프만으로는 부족합니다. 아주 중요한 함정이 하나 남아 있습니다.
서버가 죽었습니다. 클라이언트 1,000개가 동시에 실패했습니다. 전부 "1초 뒤에 다시" 규칙을 따릅니다. 그러면 1초 뒤에 무슨 일이 벌어질까요?
1,000개가 동시에 재시도합니다. 그리고 2초 뒤에 또 동시에. 4초 뒤에 또 동시에. 백오프를 넣었는데도 파도가 됩니다.
모두가 똑같은 규칙을 따르기 때문에 박자가 맞아버린 것입니다. 갓 살아난 서버가 이 파도에 다시 쓰러집니다.
해법은 일부러 어긋나게 만드는 것입니다. 대기 시간에 무작위를 섞습니다.
백오프만: 1초 → 1000개가 동시에
백오프 + 지터: 0.5~1.5초 사이 아무 때나 → 1000개가 골고루 흩어져서이것이 지터입니다. 한 줄 고치는 일인데 효과가 큽니다.
백오프는 "얼마나 자주"를 고치고, 지터는 "언제"를 고칩니다. 둘 다 있어야 합니다. 백오프만 있으면 박자 맞은 파도가 남습니다.
규칙 3 — 세 번이면 그만한다
재시도에는 한도가 있어야 합니다. 세 번 해서 안 되면 그건 일시적 문제가 아닙니다. 구조적 문제입니다. 계속 두드려도 안 됩니다.
그리고 중첩을 조심해야 합니다. 각 단계가 3번씩 재시도하는데 4단계가 겹쳐 있으면 최악의 경우 3⁴ = 81배의 부하가 됩니다. 각자는 "겨우 세 번"인데 전체로는 재앙입니다. 재시도는 사슬의 한 곳에서만 하는 것이 안전합니다.
그리고 여유가 있어야 한다
마지막으로, 백오프와 지터를 완벽히 넣어도 재시도는 부하를 늘립니다. 덜 늘릴 뿐입니다.
그래서 재시도가 있는 시스템은 평소에 여유 용량을 갖고 있어야 합니다. 평소 딱 맞게 운영하다가 재시도 폭풍이 오면 그대로 무너집니다. 여유는 낭비가 아니라 재시도의 전제 조건입니다.
직접 해보세요
아래 과제에서는 재시도 폭풍이 트래픽 급증으로 나타납니다. 평소 초당 40건이던 것이 갑자기 초당 120건이 됩니다. 이 폭풍을 견딜 여유 용량을 확보하세요.
이 강의가 단순화한 것
교육용 모형은 언제나 무언가를 생략합니다. 무엇을 생략했는지 아는 것도 학습의 일부입니다.
전제한 것
- 이 시뮬레이터는 클라이언트의 자동 재시도를 직접 수행하지 않는다. 그래서 이 과제에서 재시도 폭풍은 '갑자기 세 배로 뛰는 트래픽'으로 표현한다. 재시도가 부하를 증폭시킨다는 성질은 이 모형으로도 그대로 학습할 수 있지만, 화면의 토큰이 실제 재시도는 아니다.
- 본문의 가용성 계산(0.99 → 0.9999)은 두 번의 시도가 서로 무관하게 실패한다는 가정 위에 있다. 과부하 상황에서는 이 가정이 완전히 깨지며, 그것이 이 강의의 요점이다.
- 백오프와 지터의 대기 시간 수치는 설명을 위해 고른 대표값이며 권장 설정값이 아니다.
- 이 과제에서 폭풍의 크기(세 배)는 시나리오 설정이며, 실제 재시도 증폭 배율은 재시도 횟수와 중첩 단계 수에 따라 달라진다.
다루지 않은 것
- 지터의 구체적 방식(full jitter, equal jitter, decorrelated jitter)
- 재시도 예산(retry budget) — 전체 요청 대비 재시도 비율에 상한을 두는 기법
- 어떤 오류가 재시도 가능한지 구분하는 문제(멱등하지 않은 요청의 재시도 위험)
- 재시도와 타임아웃·서킷 브레이커의 상호작용
더 읽을거리: AWS Architecture Blog — Exponential Backoff and Jitter · Google SRE Book — Addressing Cascading Failures
이제 직접 만들어 보세요
읽어서 아는 것과 만들어서 아는 것은 다릅니다. 컴포넌트를 배치하고 트래픽을 흘려서 실제로 동작하는지 확인해 보세요.
이 강의에 물어보기
하루 5번이 강의 본문만 근거로 답합니다. 강의에 없는 내용은 지어내지 않습니다.