회사에서 사용하는 내부 최적화 엔진 API 가 특정 시간대에 자주 실패했습니다.
로그를 분석해보니 503 (Service Unavailable) 오류가 발생하는 빈도가 유독 높은 구간이 존재했고, 이는 단순히 네트워크 이슈가 아닌 서버 과부하 (CPU 바운드 작업)에 가까워 보였습니다
모니터링 결과, 기사님이 작업을 배정받기 전 배차 시뮬레이션을 통해 결과를 받아보려는 오전에 해당 오류가 많이 발생하였습니다
→ 따라서 CPU 사용률이 약 75%를 넘어서면 처리 실패 확률이 증가하는 것을 확인했습니다.
이러한 특정을 기반으로, CPU 부하를 회복할 시간을 갖도록하며 빠른 재시도는 실패율을 높이는 결과로 이어질 수 있으므로 Retry 전략을 설계하게 되었습니다
단순 재시도는 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% 증가했습니다
전체 성공률은 높아져 충분히 안정성을 확보할 수 있었지만 요청 처리 시간이 늘어나면서 사용자에게 즉시 결과를 보여주기 어려운 문제가 발생했습니다.
이를 보안하기 위해 다음과 같은 방안을 고려 중입니다.
CPU 사용률이 높은 특정 시간대에 발생했던 503 오류 문제는 Exponential Backoff + Jitter 기반 재시도 로직으로 안정성을 보안했습니다
실패율은 의미있게 감소했지만 처리 시간 증가에 대한 사용자 경험 보완이 다음 과제로 남아있습니다
실제 현상 분석부터 실험, 구현, 개선까지 이어져 단순 재시도와는 다른 설계적 접근의 중요성을 알게되어 좋은 경험이었습니다.