시스템 간 연동 (EAI) · 오류 처리와 재처리 설계 · 실습
지수 백오프·지터·DLQ 구현
목표
지수 백오프와 지터를 갖춘 재시도를 구현하고, 재시도 금지 오류를 구분하고,
DLQ 적재와 재처리 스크립트, 재시도 정책표까지 만들 수 있게 됩니다.
왜 중요한가
재시도는 공짜가 아닙니다. 게이트웨이 4회 × 서비스A 4회 × 서비스B 4회면
사용자의 클릭 한 번이 최종 시스템에 64번의 요청이 됩니다.
회복 중이던 상대는 그 폭격에 다시 쓰러집니다.
그리고 지터 없는 지수 백오프는 1만 개 클라이언트가 정확히 같은 순간에
재시도하게 만듭니다(thundering herd). 평소에는 문제가 없기 때문에
정말 큰 장애가 났을 때 처음 발견됩니다.
재시도를 '넣었다/안 넣었다'가 아니라 설계로 다루는 것이 이 실습입니다.
단계
0. 불안정 API 를 기동합니다.python3 /opt/lab/fixtures/eai/rest/flaky_api.py 9300 (백그라운드)
/flaky?key=<키>: 같은 키로 3번째 호출까지 503, 4번째부터 200/bad: 항상 400/dead: 항상 503- 각 시도 전에
attempt=<n> sleep=<초>를 한 줄 출력합니다. - 마지막 줄에는
result=<ok|fail> attempts=<n>을 출력합니다. - 환경변수
DRY=1이면 실제로 대기하지 않고 계획만 출력합니다.
1. /flaky?key=t1 을 한 번 호출한 결과를 /root/r/first.txt 에 저장합니다.http_code=503 이라는 줄이 있어야 합니다.
2. /root/r/retry.sh 를 만듭니다. 인자 두 개(URL 최대시도수)를 받아
고정 간격으로 재시도하고, 마지막 줄에 result=<ok|fail> attempts=<n> 을 출력합니다.
성공하면 종료코드 0 입니다.
3. /root/r/backoff.sh 를 만듭니다. 인자 두 개(URL 최대시도수)를 받아
지수 백오프(1, 2, 4, 8초, 상한 30초)로 재시도합니다.
4. backoff.sh 에 지터를 추가합니다. sleep 값은
계산값의 50% 이상 100% 이하의 무작위 값이어야 하고,DRY=1 로 두 번 실행하면 값이 서로 달라야 합니다.
5. backoff.sh 가 재시도 금지 오류를 구분하게 만듭니다.
HTTP 400/401/403/404/409 를 받으면 즉시 중단하고attempts=1 로 끝나야 합니다. (/bad 로 확인)
6. /root/r/senddlq.sh 를 만듭니다. 인자 두 개(URL 메시지ID)를 받아
재시도하다 최대 시도를 넘기면 /root/r/dlq/<메시지ID>.json 을 만듭니다.
JSON 에 msg_id, url, reason, attempts, first_failed_at 다섯 키가
있어야 합니다. (url 은 7단계 재처리에서 다시 호출할 대상입니다.)/dead 와 메시지 ID M-001 로 실행해 파일을 만드세요.
(같은 ID 로 다시 실행하면 같은 파일을 덮어씁니다.)
7. /root/r/dlq-replay.sh 를 만듭니다. 인자 하나(DLQ 디렉터리)를 받아
그 안의 각 .json 에 대해 재처리를 시도하고,
실패하면 해당 파일의 attempts 를 1 증가시켜 다시 저장합니다.
마지막 줄에 replayed=<시도수> succeeded=<성공수> 를 출력합니다.
디렉터리가 없으면 0 이 아닌 종료코드로 끝냅니다.
8. /root/r/policy.csv 를 만듭니다. 첫 줄은error,retry,max_attempts,backoff,final.
아래 여섯 유형이 모두 있어야 합니다.connection-refused, timeout, http-500, http-400, http-401, http-429.retry 는 Y/N/조건부, final 은 DLQ/중단/통보 중 하나입니다.
참고
- 상태코드만 얻기:
curl -s -o /dev/null -w '%{http_code}' <URL> - bash 난수:
$RANDOM(0~32767). 범위 변환에 주의하세요. - JSON 만들기:
jq -n --arg a "$A" '{msg_id:$a}'또는 printf 로 직접 - 흔한 실수 1: 재시도 루프에서 성공해도 계속 도는 것. 성공 시 즉시 break 하세요.
- 흔한 실수 2: 지터를 계산값보다 크게 만드는 것. 상한을 넘으면 백오프의 의미가 흐려집니다.
- 흔한 실수 3: DLQ 파일명을 타임스탬프로 만들어 재실행마다 파일이 늘어나는 것.
메시지 ID 기준이어야 재처리가 관리됩니다.
단계 8개
- 실패 재현
- 고정 간격 재시도
- 지수 백오프
- 지터 추가
- 재시도 금지 오류 구분
- DLQ 적재
- DLQ 재처리 스크립트
- 재시도 정책표