ALB 502·503·504 오류 원인과 해결

AWS EKS + ALB Ingress + Node.js 환경에서 HTTP 5xx 오류의 의미와 차이, 구체적인 원인과 해결 방법을 RFC 표준과 AWS 문서 기반으로 정리한다.

핵심 개념

503 — 타겟이 없다

503 Service Unavailable은 로드 밸런서가 요청을 전달할 유효한 타겟을 찾지 못했을 때 발생한다.

Kubernetes 환경에서 주요 원인:

  1. 타겟 없음: Service Selector가 Deployment 라벨과 불일치하여 Endpoints가 비어있는 경우.
  2. 타겟 비활성: Pod가 존재하지만 Readiness Probe를 통과하지 못해 ALB가 ‘Unhealthy’로 간주하는 경우.
  3. Ingress 설정 오류: 존재하지 않는 Service나 잘못된 포트를 가리키는 경우.
sequenceDiagram
    participant Client
    participant ALB
    participant TargetGroup

    Client->>ALB: HTTP Request
    ALB->>TargetGroup: Select Healthy Target
    TargetGroup-->>ALB: No Healthy Targets Available
    ALB-->>Client: 503 Service Unavailable

구분법: CloudWatch에서 HTTPCode_ELB_5XX 증가면 ALB 자체 문제, HTTPCode_Target_5XX 증가면 애플리케이션이 503을 반환한 것이다.

503 발생 시 가장 먼저 kubectl get endpoints <서비스명>을 확인한다. Endpoints가 비어있다면 Service Selector를 점검하고, 있는데 접근이 안 된다면 Pod의 Readiness Probe 설정을 확인한다.


502 — Node.js가 연결을 끊었다

502 Bad Gateway는 ALB가 백엔드로부터 유효하지 않은 응답을 받았을 때 발생한다.

가장 흔한 원인은 Keep-Alive Timeout 불일치다.

  1. Node.js의 기본 keepAliveTimeout5초, AWS ALB의 기본 idle timeout60초.
  2. ALB는 60초 동안 연결 유지를 기대하고 유휴 연결을 재사용하지만, Node.js는 5초 후 소켓을 끊어버린다.
  3. ALB가 닫힌 소켓으로 요청을 보내다 실패하여 502 Bad Gateway를 반환한다.
sequenceDiagram
    participant ALB
    participant NodeJs as Node.js App

    ALB->>NodeJs: TCP Connection Established
    Note over ALB, NodeJs: Idle (No traffic)
    NodeJs->>NodeJs: Keep-Alive Timeout (5s) Exceeded
    NodeJs--xALB: Close Connection (TCP RST/FIN)

    Note over ALB: Still thinks connection is open (Idle < 60s)
    ALB->>NodeJs: Send New Request on Closed Socket
    NodeJs-->>ALB: Connection Reset / Closed
    ALB-->>Client: 502 Bad Gateway

Node.js의 keepAliveTimeout을 ALB Idle Timeout보다 길게 설정해야 한다:

const server = app.listen(port);
server.keepAliveTimeout = 61000; // 61초
server.headersTimeout = 62000;   // keepAliveTimeout보다 커야 함

이 외에 **애플리케이션 크래시(OOM 등)**나 HTTP 헤더 크기 초과로도 502가 발생한다.


504 — 응답이 너무 느리다

504 Gateway Timeout은 ALB가 백엔드로부터 제때 응답을 받지 못했을 때 발생한다.

두 가지 조건:

  1. 연결 타임아웃: ALB가 Pod와 TCP 연결을 맺는 데 10초 이상 소요될 때. (네트워크 문제, Security Group 차단 등)
  2. 응답 타임아웃: 연결은 성공했으나 애플리케이션이 ALB Idle Timeout(60초) 내에 응답을 완료하지 못했을 때. (느린 쿼리, 외부 API 지연, 데드락 등)
sequenceDiagram
    participant Client
    participant ALB
    participant NodeJs as Node.js App

    Client->>ALB: HTTP Request
    ALB->>NodeJs: Forward Request
    Note over NodeJs: Processing (Heavy Query / External API)

    rect rgb(255, 240, 240)
        Note over ALB: Idle Timeout (60s) Exceeded
        ALB--xNodeJs: Close Connection
        ALB-->>Client: 504 Gateway Timeout
    end

    NodeJs-->>ALB: Response (Too Late)
    Note over ALB: Ignored

단순히 ALB의 Idle Timeout을 늘리는 것은 미봉책이다. 외부 API 호출이나 DB 쿼리에 명시적 타임아웃(예: 5초)을 설정하여 이벤트 루프 블로킹을 방지해야 한다.

비교·분석

오류핵심 의미주요 원인ALB/App 구분
503타겟 없음Endpoints 비어있음, Readiness Probe 실패, Ingress 오류HTTPCode_ELB_5XX
502연결 끊김Keep-Alive 불일치, 앱 크래시, 헤더 초과HTTPCode_ELB_5XX 또는 Target_5XX
504응답 지연느린 쿼리, 네트워크 차단, 이벤트 루프 블로킹항상 ALB 생성

실무 적용

디버깅 체크리스트

  1. CloudWatch 지표 확인: HTTPCode_ELB_5XX vs HTTPCode_Target_5XX 비교 — ALB 자체 문제인지 애플리케이션 응답인지 구분.
  2. Kubernetes Endpoints 확인: kubectl get endpoints <서비스명> 결과가 비어있지 않은지 확인. (503 원인)
  3. Pod 상태 및 로그 확인: kubectl get pods로 재시작 횟수 확인 및 OOMKilled 여부 점검. (502 원인)
  4. 애플리케이션 로그 분석: “Connection Reset” 에러나 쿼리 수행 시간 로그 확인.
  5. Keep-Alive 설정 검토: Node.js의 keepAliveTimeout이 ALB Idle Timeout(60s)보다 큰지 확인. (502 해결)
  6. 네트워크/보안 그룹 점검: ALB와 Worker Node 간의 Security Group 규칙 확인. (504 원인)

참고 자료