Slow Client 대응

박지예·2026년 7월 17일

공부2026

목록 보기
10/20

클라이언트에서 서버와 통신할 때 네트워크 환경이 낮은 경우 어떻게 대응할 수 있는지 학습한 방법을 정리한다.

1. 지수적 백오프

지수적 백오프 (exponential backoff)는 실패한 작업을 재시도할 때 재시도 간격을 지수적으로 늘려가는 전략이다. 네트워크 요청, 서버 연결,리소스 다운로드 처럼 일시적으로 실패할 수 있는 작업에서 특히 많이 스인다.

핵심

요청이 실패했을 때 곧바로, 그리고 일정한 간격으로 계속 재시도하면 2가지 문제가 생긴다.
이미 부하가 걸린 서버에 부담을 더 얹게 되고, 여러 클라이언트가 동시에 같은 리듬으로 재시도하면 서버가 회복할 틈이 없어진다.
그래서 재시도 할때마다 대기 시간을 기본값 x 2^재시횟수 형태로 늘려준다.

ex)
기본 대기 시간이 1초 라면

1차 실패 -> 1초 대기
2차 실패 -> 2초 대기 
3차 실패 -> 4초 대기 
4차 실패 -> 8초 대기
5차 실패 -> 16초 대기 

이렇게 하면 초반엔 빠르게 재시도해서 일시적 오류 (순간적인 패킷 손실 등)를 빠르게 넘기고, 계속 실패하면 점점 물러서면서 서버에 회복할 시간을 준다.

Jitter

순수한 지수 백오프에는 함정이 있다. 서버 장애로 1,000개의 클라이언트가 동시에 끊겼다면, 이들이 모두 정확히 1초 -> 2초 -> 4초... 같은 타이밍에 몰려서 재시도 한다. 결국 thundering herd (우르르 몰려드는 무리) 문제가 생긴다. 지수적으로 간격을 늘려도 파도가 동기화된 채로 밀려온다.

해결책이 jitter (무작위 지연) 다. 계산된 대기 시간에 랜덤성을 섞어서 재시도 타이밍을 분산시킨다.

delay = random(0,min(cap,base * 2^attempt))

실무에서

  • 기본 지연 (base delay)
  • 최대 지연 상한(cap/max delay, 무한정 커지지 않도록)
  • 최대 재시도 횟수 (max retries)
  • 그리고 재시도할 가치가 있는 오류인지 판별하는 조건 (ex. 5xx나 타임아웃은 재시도, 4xx 인증 오류는 즉시 포기)

예시 코드 ( with AI)

async UniTask<T> RetryWithBackoff<T>(
    Func<UniTask<T>> operation,
    int maxRetries = 5,
    float baseDelay = 1f,
    float maxDelay = 30f,
    CancellationToken ct = default)
{
    for (int attempt = 0; ; attempt++)
    {
        try
        {
            return await operation();
        }
        catch (Exception e) when (attempt < maxRetries && IsRetryable(e))
        {
            // 지수 계산 + 상한 + Full Jitter
            float exp = baseDelay * Mathf.Pow(2, attempt);
            float capped = Mathf.Min(exp, maxDelay);
            float delay = UnityEngine.Random.Range(0f, capped);

            await UniTask.Delay(
                TimeSpan.FromSeconds(delay),
                cancellationToken: ct);
        }
    }
}

bool IsRetryable(Exception e)
{
    // 타임아웃, 일시적 네트워크 오류만 재시도
    // 인증 실패·잘못된 요청 등은 재시도 무의미
    return e is TimeoutException || e is HttpRequestException;
}

모바일 게임에선 특히, 사용자가 지하철에서 터널을 지나거나 WIFI-LTE 전환이 일어나는 순간적 끊김이 잦기 때문에 백오프가 잘 동작하면 체감 안정성이 크게 올라간다.
다만 백오프가 진행되는 동안 사용자에게 "재연결 중" 같은 피드백을 UI로 보여주지 않으면 앱이 멈춘 것처럼 느껴질 수 있어서, 재시도 상태를 ViewModel에 노출해두는 편이 좋다.

주의

모든 실패에 지수 백오프를 거는 건 오히려 나쁘다. 400번대 클라이언트 오류(잘못된 파라미터, 인증 만료 등)는 몇 번을 재시도해도 결과가 같으므로 즉시 실패처리하거나 다른 복구 경로(토큰 갱신)로 보내야 한다. 언제까지나 일시적 오류에만 의미가 있다.

profile
게임 클라이언트 개발자

0개의 댓글