Retry with Exponential Backoff & Jitter

이명규·2025년 5월 23일

CPU 바운드 작업으로 인해 종종 실패하는 외부 API

회사에서 사용하는 내부 최적화 엔진 API 가 특정 시간대에 자주 실패했습니다.
로그를 분석해보니 503 (Service Unavailable) 오류가 발생하는 빈도가 유독 높은 구간이 존재했고, 이는 단순히 네트워크 이슈가 아닌 서버 과부하 (CPU 바운드 작업)에 가까워 보였습니다

모니터링 결과, 기사님이 작업을 배정받기 전 배차 시뮬레이션을 통해 결과를 받아보려는 오전에 해당 오류가 많이 발생하였습니다

  • 오전 11시 ~ 12시 : 요청 급증 + 외부 엔진 CPU 사용류 약 75% 이상 → 503 오류 빈발
  • 오후 시간대 요청시 정상 응답 다수 확인

→ 따라서 CPU 사용률이 약 75%를 넘어서면 처리 실패 확률이 증가하는 것을 확인했습니다.

이러한 특정을 기반으로, CPU 부하를 회복할 시간을 갖도록하며 빠른 재시도는 실패율을 높이는 결과로 이어질 수 있으므로 Retry 전략을 설계하게 되었습니다



Retry 전략 - Exponential Backoff + Jitter

단순 재시도는 API 서버에 더 큰 부하를 줄 수 있기 때문에 이를 방지하기 위해 지수형 백오프와 지터(Jitter) 를 함께 적용했습니다

지수형 백오프의 구현 형태는 아래와 같습니다

private fun calculateExponentialBackoff(retryCount: Int): Long {
    val delay = (INITIAL_RETRY_DELAY_MS * BACKOFF_MULTIPLIER.pow(retryCount.toDouble())).toLong()
    return min(delay, MAX_RETRY_DELAY_MS)
}
  • 초기 지연시간이 존재하고 여기에 재시도 횟수에 따라 지수적으로 증가하도록 처리되었습니다
  • 이후 최대 지연시간을 설정하여 계산된 지연시간이 최대 지연시간을 넘어간 경우 최대 지연시간을 사용하도록 구현되었습니다


Jitter 적용

private fun addJitter(baseDelayMs: Long): Long {
    val jitterRange = (baseDelayMs * JITTER_FACTOR).toLong()
    return baseDelayMs + Random.nextLong(-jitterRange, jitterRange)
}
  • 계산된 지연시간에 무작위성을 적용하였습니다
  • 서버가 이중화되어 있으므로 동일한 지연시간을 갖게 된 경우 실패확률이 올라가게 됩니다
  • 그러므로 랜덤성을 부여하여 최대한 동일한 시간에 여러 서버가 요청하지 않도록 무작위성을 추가하였습니다


실제 적용 효과

재시도 로직을 적용한 후, 다음과 같은 성과를 확인할 수 있었습니다

오전 11시 ~ 12시간대 기준 재시도 로직 주요 수치

항목적용 전적용 후변화율
평균 실패율약 20%약 2.5%↓ 약 87% 감소
평균 처리 시간약 1.5초평균 4초 (2~6초)↑ 약 167% 증가

결과적으로 평균 실패율은 대략 87 % 감소했고 반대로 평균 요청 처리는 대략 167% 증가했습니다


후속 개선 방향

전체 성공률은 높아져 충분히 안정성을 확보할 수 있었지만 요청 처리 시간이 늘어나면서 사용자에게 즉시 결과를 보여주기 어려운 문제가 발생했습니다.

이를 보안하기 위해 다음과 같은 방안을 고려 중입니다.

  • 비동기 요청 + Progress UI
    • 사용자에게 응답을 블로킹하지 않도록 처리 상태 시각화
  • 대량 배차 요청에 대한 배치 처리 도입
    • 일반적인 기사 배차는 하루 단위로 적은 양이지만, 일부 기업 고객의 경우 주간/월간 단위 대량 배차 수요가 있어 예약/배차 기반 비동기 처리 시스템 을 고려

정리

CPU 사용률이 높은 특정 시간대에 발생했던 503 오류 문제는 Exponential Backoff + Jitter 기반 재시도 로직으로 안정성을 보안했습니다

실패율은 의미있게 감소했지만 처리 시간 증가에 대한 사용자 경험 보완이 다음 과제로 남아있습니다

실제 현상 분석부터 실험, 구현, 개선까지 이어져 단순 재시도와는 다른 설계적 접근의 중요성을 알게되어 좋은 경험이었습니다.

profile
개발자

0개의 댓글