Gateway Timeout 발생했을 때 대응 방법: HTTP 504 원인 분석과 실무 점검 순서

Gateway timeout은 단순히 “서버가 느리다”로 끝낼 문제가 아닙니다. HTTP 요청이 여러 구간을 지나가는 구조에서는 웹 서버, 프록시, 로드밸런서, 애플리케이션 서버, 외부 API 중 어느 지점에서 응답이 지연됐는지 나누어 봐야 합니다.

백엔드 서비스를 운영하다 보면 가끔 504 Gateway Timeout을 만나게 됩니다. 화면에는 Gateway timeout이라고만 보이지만, 실제 원인은 생각보다 다양합니다.

중요한 점은 504가 보였다고 해서 반드시 애플리케이션 서버가 죽었다는 뜻은 아니라는 점입니다. 중간에 있는 게이트웨이나 프록시가 뒤쪽 서버로부터 정해진 시간 안에 응답을 받지 못했을 때 발생하는 경우가 많습니다.

Gateway timeout이 무엇인지, HTTP 요청 흐름에서 어디를 봐야 하는지, 그리고 실무에서 어떤 순서로 대응하면 좋은지 정리하겠습니다.

 

HTTP Gateway Timeout은 무엇인가요?

HTTP Gateway timeout은 보통 504 상태 코드로 표현됩니다. 클라이언트가 직접 호출한 서버가 최종 응답을 만들지 못했다기보다는, 중간에 있는 서버가 뒤쪽 서버의 응답을 기다리다가 제한 시간을 넘겼다는 의미에 가깝습니다.

예를 들어 사용자가 브라우저에서 API를 호출하면 요청은 다음과 같은 흐름을 탈 수 있습니다.


Client
  -> CDN
  -> Load Balancer
  -> Nginx
  -> Spring Boot Application
  -> Database or External API

이 구조에서 Nginx가 Spring Boot 애플리케이션의 응답을 일정 시간 안에 받지 못하면 504를 반환할 수 있습니다. 로드밸런서가 Nginx나 애플리케이션 서버의 응답을 기다리다 실패해도 같은 현상이 나타날 수 있습니다.

그래서 Gateway timeout을 볼 때는 “어느 서버가 느렸나?”보다 “어느 구간에서 기다리다 끊겼나?”를 먼저 확인하는 편이 낫습니다.

 

Gateway Timeout이 발생하는 대표 원인

Gateway timeout은 네트워크, HTTP 설정, 애플리케이션 처리 시간, 외부 연동 지연 등 여러 이유로 발생합니다. 원인을 하나로 단정하면 점검 방향이 틀어질 수 있습니다.

1. 애플리케이션 응답 시간이 너무 긴 경우

가장 흔한 경우는 애플리케이션 서버가 요청을 받았지만, 처리 시간이 프록시나 로드밸런서의 timeout보다 길어진 상황입니다.

예를 들어 Spring Boot API가 내부에서 복잡한 조회를 하거나, 외부 결제사 API를 기다리거나, 파일 생성 작업을 동기 방식으로 처리하고 있다면 응답 시간이 길어질 수 있습니다. 이때 애플리케이션은 아직 작업 중이지만 앞단의 게이트웨이는 이미 기다림을 포기할 수 있습니다.


Client -> Gateway -> Application

Gateway timeout: 30초
Application processing time: 45초

결과: Gateway는 30초 후 504 반환
Application은 뒤에서 계속 처리 중일 수 있음

이 경우 timeout 설정만 늘리면 일시적으로 증상은 줄어들 수 있습니다. 하지만 요청 자체가 오래 걸리는 이유를 함께 봐야 합니다. 단순 조회 API인지, 배치성 작업인지, 외부 연동이 포함된 API인지에 따라 해결 방식이 달라집니다.

2. 프록시 또는 로드밸런서 timeout 설정이 짧은 경우

애플리케이션이 정상적으로 동작하더라도 앞단 timeout 설정이 짧으면 Gateway timeout이 발생할 수 있습니다. 특히 Nginx, AWS ALB, API Gateway, CloudFront 같은 구간이 함께 있으면 각 계층의 timeout이 서로 다를 수 있습니다.

실무에서는 이 부분을 자주 놓칩니다. 애플리케이션의 HTTP client timeout만 확인하고, 정작 로드밸런서 idle timeout이나 Nginx proxy timeout을 보지 않는 경우가 있습니다.


Nginx 예시

proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;

위 설정에서 proxy_read_timeout은 Nginx가 upstream 서버의 응답을 기다리는 시간과 관련이 있습니다. 애플리케이션 API가 40초 걸린다면 Nginx는 30초 지점에서 504를 반환할 수 있습니다.

3. 외부 API 응답 지연

내 서비스의 API가 내부에서 외부 API를 호출하는 구조라면, Gateway timeout의 원인이 내 서버 바깥에 있을 수 있습니다.

예를 들어 결제 승인, 주소 검색, 알림 발송, 인증 서버 호출처럼 외부 네트워크를 타는 로직이 포함되어 있으면 응답 지연이 전파됩니다. 사용자는 내 서비스에서 504를 보지만, 실제 병목은 외부 API 응답 지연일 수 있습니다.


Client
  -> My API
      -> External API 응답 지연
  -> Gateway timeout

이 상황에서는 외부 API 호출 timeout을 명확히 잡아야 합니다. 무한정 기다리거나 지나치게 긴 timeout을 주면 앞단 Gateway timeout과 충돌하기 쉽습니다.

4. 네트워크 연결 문제

Gateway timeout은 네트워크 문제로도 발생할 수 있습니다. DNS 조회 지연, 방화벽 설정, 보안 그룹, 라우팅 문제, VPC 내부 통신 문제 등이 원인이 될 수 있습니다.

특히 클라우드 환경에서는 서버 자체는 살아 있는데 특정 경로에서만 연결이 안 되는 일이 있습니다. 이때 애플리케이션 로그만 보면 요청이 아예 들어오지 않은 것처럼 보일 수 있습니다.

요청이 애플리케이션까지 도착했는지, 로드밸런서에서는 어떤 상태로 기록됐는지, Nginx access log와 error log에는 어떤 upstream 정보가 남았는지 함께 확인해야 합니다.

 

Gateway Timeout 대응 순서

Gateway timeout이 발생했을 때는 감으로 설정을 바꾸기보다 요청 흐름을 앞에서 뒤로 따라가는 방식이 좋습니다. 어느 계층이 504를 만들었는지 찾는 것이 먼저입니다.

1. 504를 반환한 주체 확인

먼저 504 응답을 누가 반환했는지 확인해야 합니다. 브라우저나 API 클라이언트에서 보이는 504 메시지만으로는 원인을 확정할 수 없습니다.

응답 헤더를 보면 힌트를 얻을 수 있습니다. Server 헤더, Via 헤더, CDN 관련 헤더, 로드밸런서 로그 등을 함께 확인합니다.


curl -v https://api.example.com/orders/123

curl의 verbose 옵션을 사용하면 연결 과정, 응답 헤더, TLS 연결 여부 등을 확인할 수 있습니다. 간단하지만 장애 초기에 방향을 잡는 데 도움이 됩니다.

2. 애플리케이션 로그에 요청이 도착했는지 확인

다음은 애플리케이션 로그입니다. 요청 ID나 trace ID가 있다면 해당 요청이 애플리케이션까지 도착했는지 확인합니다.

요청이 애플리케이션 로그에 없다면 앞단 네트워크, 로드밸런서, 프록시 구간을 의심해야 합니다. 반대로 로그가 남아 있고 처리 시간이 길다면 애플리케이션 내부 로직을 봐야 합니다.


예시 로그

2026-05-30 10:15:12 INFO  requestId=abc-123 uri=/orders/123 start
2026-05-30 10:15:45 INFO  requestId=abc-123 uri=/orders/123 end elapsed=33000ms

이런 로그가 있다면 API 자체가 33초 걸렸다는 뜻입니다. 앞단 timeout이 30초라면 사용자는 504를 보았을 가능성이 높습니다.

3. 프록시와 로드밸런서 로그 확인

Gateway timeout에서는 프록시 로그가 중요합니다. Nginx를 사용한다면 access log에 upstream 응답 시간, 상태 코드, 요청 시간을 남겨두는 편이 좋습니다.


Nginx log_format 예시

log_format main '$remote_addr - $request '
                'status=$status '
                'request_time=$request_time '
                'upstream_status=$upstream_status '
                'upstream_response_time=$upstream_response_time';

이 로그를 남겨두면 Nginx가 실제로 upstream에서 응답을 받았는지, 얼마나 기다렸는지 확인할 수 있습니다. 장애가 난 다음에 로그 포맷을 바꾸면 이미 지나간 요청은 분석하기 어렵습니다.

AWS ALB를 사용한다면 target_status_code, elb_status_code, target_processing_time 같은 값을 확인합니다. elb_status_code가 504이고 target_status_code가 비어 있거나 비정상이라면 로드밸런서가 target 응답을 정상적으로 받지 못한 상황일 수 있습니다.

4. timeout 설정을 계층별로 정리

Gateway timeout을 제대로 대응하려면 각 계층의 timeout 값을 표처럼 정리하는 것이 좋습니다. 설정이 여러 곳에 흩어져 있으면 어느 값이 먼저 끊는지 판단하기 어렵습니다.

구간 확인할 timeout 점검 포인트
CDN Origin response timeout Origin 서버 응답 대기 시간
Load Balancer Idle timeout Target과 연결 유지 시간
Nginx proxy_connect_timeout, proxy_read_timeout upstream 연결 및 응답 대기 시간
Application server timeout, async timeout 요청 처리 제한 시간
HTTP Client connect timeout, read timeout 외부 API 호출 제한 시간

timeout은 길게 잡는다고 항상 좋은 것은 아닙니다. 앞단은 짧고 뒤쪽은 길게 잡혀 있으면 사용자는 이미 실패 응답을 받았는데 애플리케이션은 계속 작업하는 상태가 될 수 있습니다.

반대로 뒤쪽 HTTP client timeout이 너무 길면 외부 API 지연이 그대로 내 API 응답 지연으로 이어질 수 있습니다. 전체 요청 흐름을 기준으로 일관성 있게 맞추는 것이 중요합니다.

 

Spring Boot에서 확인할 부분

Gateway timeout이 Spring Boot API에서 발생한다면 애플리케이션 내부 처리 시간과 외부 호출 timeout을 함께 봐야 합니다. HTTP 서버 설정만 보고 끝내면 원인을 놓칠 수 있습니다.

요청 처리 시간이 긴 API 찾기

먼저 API별 처리 시간을 로그나 APM으로 확인합니다. 특정 endpoint에서만 504가 발생한다면 해당 API의 내부 로직을 보는 것이 빠릅니다.


@Component
public class RequestLoggingFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain
    ) throws ServletException, IOException {

        long start = System.currentTimeMillis();

        try {
            filterChain.doFilter(request, response);
        } finally {
            long elapsed = System.currentTimeMillis() - start;

            log.info("uri={}, status={}, elapsed={}ms",
                    request.getRequestURI(),
                    response.getStatus(),
                    elapsed);
        }
    }
}

위 코드는 단순 예시입니다. 실제 서비스에서는 requestId, userId, method, query string 포함 여부 등을 팀 기준에 맞게 조정합니다. 다만 개인정보나 민감 정보가 로그에 남지 않도록 주의해야 합니다.

외부 API timeout 명시하기

외부 API를 호출한다면 connect timeout과 read timeout을 명확히 설정해야 합니다. timeout을 명시하지 않으면 라이브러리 기본값에 의존하게 되고, 이 값이 서비스 기대와 맞지 않을 수 있습니다.


@Configuration
public class RestClientConfig {

    @Bean
    public RestClient restClient() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();

        factory.setConnectTimeout(Duration.ofSeconds(3));
        factory.setReadTimeout(Duration.ofSeconds(5));

        return RestClient.builder()
                .requestFactory(factory)
                .build();
    }
}

connect timeout은 연결을 맺는 데 허용할 시간이고, read timeout은 연결 후 응답을 읽기까지 기다리는 시간입니다. 둘을 구분하지 않으면 네트워크 연결 문제와 외부 서버 응답 지연을 같은 문제로 착각하기 쉽습니다.

외부 API 호출은 실패할 수 있다는 전제를 두는 편이 좋습니다. 재시도, fallback, 에러 응답 처리, 비동기 처리 전환 여부를 함께 검토해야 합니다.

 

Gateway Timeout 해결 방법

Gateway timeout 해결은 크게 두 방향입니다. 하나는 timeout 설정을 조정하는 것이고, 다른 하나는 요청 처리 방식을 바꾸는 것입니다. 대부분은 둘을 함께 봐야 합니다.

1. timeout 설정을 무작정 늘리지 않기

가장 쉬운 대응은 timeout 값을 늘리는 것입니다. 하지만 이것만으로 문제를 덮으면 나중에 더 긴 대기, 중복 요청, 사용자 경험 저하로 이어질 수 있습니다.

조회 API라면 응답 시간이 왜 길어졌는지 확인해야 합니다. 외부 API 호출이라면 외부 시스템의 지연을 어디까지 기다릴지 기준이 필요합니다. 파일 생성이나 대량 처리처럼 오래 걸리는 작업이라면 동기 HTTP 요청으로 처리하는 방식 자체가 맞는지 검토해야 합니다.

2. 오래 걸리는 작업은 비동기로 분리하기

사용자가 즉시 결과를 받을 필요가 없는 작업은 비동기로 분리하는 편이 낫습니다. HTTP 요청 안에서 모든 일을 끝내려 하면 Gateway timeout에 취약해집니다.


동기 처리

POST /reports
  -> 보고서 생성
  -> 파일 저장
  -> 응답 반환

비동기 처리

POST /reports
  -> 작업 요청 저장
  -> jobId 반환

GET /reports/{jobId}
  -> 작업 상태 조회

보고서 생성, 대량 엑셀 다운로드, 외부 시스템 동기화 같은 작업은 비동기 구조가 더 잘 맞는 경우가 많습니다. 사용자는 jobId를 받고 상태를 조회하거나, 완료 알림을 받는 방식으로 처리할 수 있습니다.

3. 외부 API 호출에는 실패 전략을 둔다

외부 API가 느려졌을 때 내 서비스까지 함께 느려지는 구조는 위험합니다. 호출 timeout을 짧게 잡고, 실패 시 사용자에게 어떤 응답을 줄지 정해야 합니다.

예를 들어 부가 정보 조회에 실패한 경우라면 기본 정보만 먼저 내려줄 수 있습니다. 반대로 결제 승인처럼 반드시 성공 여부를 확인해야 하는 경우라면 짧은 timeout과 명확한 실패 처리, 재조회 또는 보정 프로세스가 필요합니다.

여기서 중요한 것은 모든 외부 API를 같은 기준으로 보지 않는 것입니다. 기능의 중요도에 따라 기다릴 수 있는 시간과 실패 처리 방식이 달라져야 합니다.

4. 재시도는 신중하게 적용하기

Gateway timeout이 발생했다고 해서 무조건 재시도하면 문제가 더 커질 수 있습니다. 특히 서버에서는 처리가 계속 진행 중인데 클라이언트나 중간 서버가 다시 요청을 보내면 중복 처리가 발생할 수 있습니다.

결제, 주문, 쿠폰 발급처럼 상태가 변경되는 API는 idempotency key를 사용하거나 중복 요청을 방지하는 장치가 필요합니다.


POST /payments
Idempotency-Key: order-20260530-0001

이런 키가 있으면 같은 요청이 여러 번 들어와도 서버에서 하나의 요청으로 처리할 수 있습니다. 단순 조회 API와 상태 변경 API는 재시도 전략을 다르게 가져가는 편이 안전합니다.

 

Gateway Timeout 점검 체크리스트

Gateway timeout이 발생했을 때는 아래 순서로 확인하면 원인 범위를 빠르게 좁힐 수 있습니다.

순서 점검 항목 확인 내용
1 응답 주체 확인 CDN, 로드밸런서, Nginx, 애플리케이션 중 어디서 504가 반환됐는지 확인
2 요청 도착 여부 애플리케이션 로그에 해당 요청이 남았는지 확인
3 처리 시간 확인 API endpoint별 응답 시간, 외부 API 호출 시간 확인
4 timeout 설정 비교 CDN, LB, Nginx, Application, HTTP Client timeout 비교
5 외부 의존성 확인 외부 API, DB, 인증 서버, 파일 서버 응답 지연 여부 확인
6 처리 방식 재검토 동기 처리 유지 여부, 비동기 분리 가능성 검토

이 체크리스트에서 중요한 기준은 요청이 어디까지 갔는지입니다. 애플리케이션까지 도착하지 않았다면 네트워크와 프록시 구간을 먼저 봐야 하고, 도착했다면 내부 처리 시간과 의존성을 봐야 합니다.

 

Gateway Timeout을 줄이기 위한 운영 습관

Gateway timeout은 장애가 난 뒤에만 대응하면 매번 원인 추적이 길어집니다. 평소에 로그와 timeout 기준을 정리해두면 문제 발생 시 훨씬 빠르게 판단할 수 있습니다.

요청 ID를 끝까지 전달하기

CDN, 로드밸런서, Nginx, 애플리케이션 로그가 서로 따로 놀면 하나의 요청을 추적하기 어렵습니다. requestId나 traceId를 헤더로 전달하고, 각 계층 로그에 남기는 방식이 좋습니다.


X-Request-Id: 9f1c1b8a-7e22-4f11-8a98-2d0f5a1c2b77

요청 ID가 있으면 사용자가 504를 본 시점의 로그를 각 계층에서 연결해 볼 수 있습니다. 협업할 때도 “대략 이 시간쯤 느렸습니다”보다 훨씬 명확하게 대화할 수 있습니다.

긴 작업과 짧은 API를 구분하기

모든 기능을 HTTP 요청 하나로 끝내려고 하면 timeout 문제에 취약해집니다. 사용자가 즉시 봐야 하는 결과와 나중에 받아도 되는 결과를 나누어야 합니다.

조회, 저장, 검증처럼 짧게 끝나야 하는 API는 응답 시간을 관리해야 합니다. 반면 리포트 생성, 대량 처리, 외부 시스템 동기화처럼 오래 걸릴 수 있는 작업은 작업 큐나 상태 조회 방식으로 분리하는 편이 유지보수에 좋습니다.

timeout 기준을 문서화하기

팀에서 timeout 기준을 정리해두지 않으면 각 개발자가 다른 기준으로 값을 설정하게 됩니다. 어떤 외부 API는 3초, 어떤 API는 60초를 기다리는 식으로 흩어지면 장애 대응 시 판단이 어려워집니다.

서비스 성격에 맞게 기본 connect timeout, read timeout, 재시도 횟수, 재시도 간격, 실패 처리 방식을 문서화해두는 것이 좋습니다. 이 문서는 길 필요가 없습니다. 중요한 것은 팀이 같은 기준으로 코드를 작성하는 것입니다.

 

마무리: Gateway Timeout은 구간을 나누어 봐야 합니다

Gateway timeout은 HTTP 요청 흐름 중간에서 뒤쪽 서버의 응답을 기다리다 실패한 상태입니다. 따라서 단순히 애플리케이션 서버가 느리다고 단정하기보다 CDN, 로드밸런서, 프록시, 애플리케이션, 외부 API 구간을 나누어 확인해야 합니다.

가장 먼저 504를 반환한 주체를 확인하고, 요청이 애플리케이션까지 도착했는지 봅니다. 그다음 API 처리 시간, 외부 API 호출 시간, 계층별 timeout 설정을 비교하면 원인 범위가 좁혀집니다.

해결 방법도 timeout을 늘리는 것만이 답은 아닙니다. 오래 걸리는 작업은 비동기로 분리하고, 외부 API 호출에는 명확한 timeout과 실패 전략을 두어야 합니다. 상태 변경 API라면 재시도와 중복 처리까지 함께 고려해야 합니다.

Gateway timeout 대응의 핵심은 “어디서 끊겼는지”를 찾는 것입니다. 이 기준만 잡혀도 HTTP 네트워크 문제를 훨씬 차분하게 분석할 수 있습니다.

정리하면 Gateway timeout은 HTTP, 네트워크, 서버 처리 시간, 외부 의존성이 함께 얽힌 문제입니다. 로그와 timeout 설정을 계층별로 정리해두면 장애 상황에서도 원인을 빠르게 좁힐 수 있습니다.