배포 직후 ALB에서 502가 터지기 시작했습니다. Target Group은 healthy인데 왜 502일까요? ALB 502는 원인이 다양하고, 증상만으로는 구분이 어렵습니다. 이 글에서는 원인별 진단 흐름과 해결 방법을 정리합니다.
핵심 요약
| 원인 | 증상 | 확인 방법 |
|---|---|---|
| Target이 모두 unhealthy | 모든 요청에서 502 | Target Group Health Check 상태 확인 |
| 백엔드가 연결을 먼저 끊음 | 간헐적 502 | ALB Access Log의 target_status_code 확인 |
| 백엔드 응답 타임아웃 | 특정 요청에서 502 | ALB idle timeout vs 백엔드 timeout 비교 |
| Target 등록/해제 중 | 배포 직후 502 | Deregistration delay 설정 확인 |
| 백엔드 Keep-Alive < ALB idle timeout | 간헐적 502 (부하 시) | 백엔드 Keep-Alive 설정 확인 |
| Security Group/NACL 차단 | 지속적 502 | Health Check port 허용 여부 확인 |
1. ALB 502 Bad Gateway란
ALB가 클라이언트 요청을 백엔드(Target)로 전달했지만, 정상적인 응답을 받지 못했을 때 반환하는 HTTP 상태 코드입니다.
핵심 포인트: 502는 ALB 자체의 문제가 아니라, ALB와 백엔드 사이의 통신 문제입니다.
ALB가 502를 반환하는 조건:
- Target에 연결을 시도했지만 TCP 연결 자체가 실패한 경우
- Target이 연결을 수립한 후 응답 없이 연결을 끊은 경우
- Target이 잘못된 형식의 HTTP 응답을 반환한 경우
- 모든 Target이 unhealthy 상태인 경우
2. 원인별 분석
2-1. 모든 Target이 unhealthy
가장 흔한 원인입니다. Target Group에 등록된 모든 인스턴스가 Health Check에 실패하면, ALB는 요청을 전달할 대상이 없어 502를 반환합니다.
확인 방법:
aws elbv2 describe-target-health \
--target-group-arn arn:aws:elasticloadbalancing:ap-northeast-2:123456789012:targetgroup/my-tg/abc123
출력 예시 (unhealthy):
{
"TargetHealthDescriptions": [
{
"Target": { "Id": "i-0abc123", "Port": 8080 },
"TargetHealth": {
"State": "unhealthy",
"Reason": "Target.ResponseCodeMismatch",
"Description": "Health checks failed with these codes: [503]"
}
}
]
}
주요 원인:
- 애플리케이션이 Health Check 경로에서 200을 반환하지 않음
- Health Check port와 애플리케이션 리스닝 port가 다름
- Security Group이 Health Check 트래픽을 차단
- 애플리케이션 시작 시간이 Health Check interval보다 김
해결:
# Health Check 설정 확인
aws elbv2 describe-target-groups \
--target-group-arns arn:aws:elasticloadbalancing:ap-northeast-2:123456789012:targetgroup/my-tg/abc123 \
--query 'TargetGroups[0].{Path:HealthCheckPath,Port:HealthCheckPort,Interval:HealthCheckIntervalSeconds,Threshold:UnhealthyThresholdCount}'
2-2. 백엔드가 연결을 먼저 끊음 (Connection Reset)
ALB가 기존 TCP 연결을 재사용하려고 요청을 보냈는데, 백엔드가 이미 그 연결을 닫은 경우입니다. 이 상황은 ALB Access Log에서 target_status_code가 -로 기록됩니다.
실무 시나리오:
Nginx를 리버스 프록시로 사용하는 환경에서, Nginx의 keepalive_timeout이 60초이고 ALB의 idle timeout이 60초인 경우를 생각해봅니다. 두 값이 같으면 Nginx가 연결을 닫는 시점과 ALB가 요청을 보내는 시점이 겹칠 수 있습니다. 이때 race condition이 발생하여 간헐적 502가 나타납니다.
ALB Access Log 확인:
# target_status_code가 "-"인 경우 = 백엔드가 응답 전에 연결을 끊음
# elb_status_code가 502인 로그 필터링
grep "502" alb-access-log.txt | awk '{print $9, $10}'
해결:
백엔드의 Keep-Alive timeout을 ALB idle timeout보다 크게 설정합니다.
# Nginx 설정 예시
# ALB idle timeout: 60초 → Nginx keepalive_timeout: 65초 이상
keepalive_timeout 65;
# Spring Boot 설정 예시
server:
tomcat:
keep-alive-timeout: 65000 # 65초 (ALB idle timeout 60초보다 큼)
2-3. 백엔드 응답 타임아웃
ALB의 idle timeout(기본 60초) 내에 백엔드가 응답을 시작하지 않으면 502를 반환합니다.
실무 시나리오:
대용량 리포트를 생성하는 API가 있습니다. DB 쿼리에 45초, 데이터 가공에 20초가 걸려 총 65초가 소요됩니다. ALB idle timeout이 기본 60초이므로, ALB는 60초 시점에 연결을 끊고 502를 반환합니다.
확인 방법:
# ALB idle timeout 확인
aws elbv2 describe-load-balancer-attributes \
--load-balancer-arn arn:aws:elasticloadbalancing:ap-northeast-2:123456789012:loadbalancer/app/my-alb/abc123 \
--query 'Attributes[?Key==`idle_timeout.timeout_seconds`].Value'
해결:
# ALB idle timeout 증가 (최대 4000초)
aws elbv2 modify-load-balancer-attributes \
--load-balancer-arn arn:aws:elasticloadbalancing:ap-northeast-2:123456789012:loadbalancer/app/my-alb/abc123 \
--attributes Key=idle_timeout.timeout_seconds,Value=120
idle timeout을 무작정 늘리면 연결이 오래 유지되어 ALB 리소스를 소모합니다. 장시간 처리가 필요한 요청은 비동기 패턴(SQS + Worker)으로 분리하는 것이 운영 관점에서 적합합니다.
2-4. 배포 중 Target 등록/해제 (Deregistration Delay)
Rolling 배포 시 기존 Target이 해제되고 새 Target이 등록되는 과정에서 502가 발생할 수 있습니다.
발생 흐름:
- 배포 시작 → 기존 인스턴스 Target Group에서 해제 시작
- Deregistration delay 동안 기존 연결은 유지되지만, 새 요청은 전달되지 않음
- 새 인스턴스가 등록되었지만 아직 Health Check를 통과하지 못한 상태
- 이 시점에 healthy Target이 0개가 되면 502 발생
확인 방법:
# Deregistration delay 확인 (기본 300초)
aws elbv2 describe-target-group-attributes \
--target-group-arn arn:aws:elasticloadbalancing:ap-northeast-2:123456789012:targetgroup/my-tg/abc123 \
--query 'Attributes[?Key==`deregistration_delay.timeout_seconds`].Value'
해결:
- Health Check의
HealthyThresholdCount를 줄여 새 Target이 빨리 healthy가 되도록 설정 - 배포 전략에서 최소 healthy Target 수를 보장 (예: ECS minimum healthy percent 100%)
- Deregistration delay를 애플리케이션의 평균 요청 처리 시간에 맞게 조정
2-5. Security Group / NACL 설정 오류
ALB와 Target 간 네트워크 통신이 차단되면 Health Check가 실패하고 502가 발생합니다.
확인 체크리스트:
| 확인 항목 | 설명 |
|---|---|
| Target의 Security Group Inbound | ALB의 Security Group에서 오는 트래픽 허용 여부 |
| Health Check Port | Target SG에서 Health Check port 허용 여부 |
| NACL Inbound/Outbound | Subnet 레벨에서 양방향 트래픽 허용 여부 |
| Ephemeral Port | NACL Outbound에서 1024-65535 허용 여부 |
올바른 Security Group 설정 예시:
# Target EC2의 Security Group: ALB SG에서 오는 트래픽 허용
aws ec2 authorize-security-group-ingress \
--group-id sg-target-123 \
--protocol tcp \
--port 8080 \
--source-group sg-alb-456
3. 진단 흐름
502가 발생했을 때 아래 순서로 원인을 좁혀갑니다.
Step 1: Target Health 확인
aws elbv2 describe-target-health --target-group-arn <TG_ARN>
- 모든 Target이 unhealthy → 2-1 참고
- healthy Target이 있는데 502 → Step 2로
Step 2: ALB Access Log 분석
# S3에서 Access Log 다운로드 후 분석
# target_status_code 확인
# "-" = 백엔드가 응답 전에 연결 끊음 → 2-2 참고
# "0" = 타임아웃 → 2-3 참고
Step 3: CloudWatch 메트릭 확인
# HTTPCode_ELB_502_Count 메트릭으로 발생 패턴 확인
aws cloudwatch get-metric-statistics \
--namespace AWS/ApplicationELB \
--metric-name HTTPCode_ELB_502_Count \
--dimensions Name=LoadBalancer,Value=app/my-alb/abc123 \
--start-time 2026-05-31T00:00:00Z \
--end-time 2026-05-31T23:59:59Z \
--period 300 \
--statistics Sum
- 배포 시점에 집중 → 2-4 참고
- 부하 증가 시 발생 → 2-2 (Keep-Alive race condition) 참고
- 특정 API에서만 발생 → 2-3 (타임아웃) 참고
Step 4: 네트워크 확인
- Security Group, NACL 규칙 점검 → 2-5 참고
4. 실무 시나리오: 배포 후 간헐적 502
상황: ECS Fargate에서 Rolling 배포 후 약 30초간 502가 간헐적으로 발생합니다.
진단 과정:
- Target Health 확인 → 배포 중 일시적으로 healthy Target이 0개가 되는 구간 발견
- ECS Task 시작 시간: 약 25초 (컨테이너 pull + 애플리케이션 시작)
- Health Check 설정: interval 30초, healthy threshold 3회 → 최소 90초 후 healthy
- 기존 Task 해제 + 새 Task healthy 전환 사이에 공백 발생
해결:
{
"healthCheck": {
"path": "/health",
"interval": 10,
"timeout": 5,
"healthyThresholdCount": 2,
"unhealthyThresholdCount": 3
}
}
- Health Check interval: 30초 → 10초
- Healthy threshold: 3회 → 2회
- 최소 healthy 전환 시간: 90초 → 20초로 단축
- ECS minimum healthy percent: 100% 유지 (기존 Task를 새 Task가 healthy 될 때까지 유지)
5. ALB Access Log 활성화
502 원인 분석에서 Access Log는 핵심 진단 도구입니다. 운영 환경에서는 반드시 활성화해야 합니다.
# Access Log 활성화
aws elbv2 modify-load-balancer-attributes \
--load-balancer-arn <ALB_ARN> \
--attributes \
Key=access_logs.s3.enabled,Value=true \
Key=access_logs.s3.bucket,Value=my-alb-logs-bucket \
Key=access_logs.s3.prefix,Value=alb-logs
Access Log 주요 필드:
| 필드 | 설명 | 502 진단 활용 |
|---|---|---|
| elb_status_code | ALB가 클라이언트에 반환한 상태 코드 | 502 필터링 |
| target_status_code | 백엔드가 ALB에 반환한 상태 코드 | -: 연결 끊김, 숫자: 백엔드 에러 |
| request_processing_time | ALB가 요청을 받고 Target에 전달하기까지 시간 | -1이면 Target 전달 실패 |
| target_processing_time | Target이 요청을 받고 응답하기까지 시간 | -1이면 응답 없음 (타임아웃) |
| response_processing_time | ALB가 응답을 받고 클라이언트에 전달하기까지 시간 | -1이면 전달 실패 |
Access Log는 5분 단위로 S3에 저장됩니다. 실시간 분석이 필요하면 CloudWatch Logs로 전송하거나, Athena 테이블을 미리 생성해두면 빠르게 쿼리할 수 있습니다.
6. 재발 방지 체크리스트
| 항목 | 권장 설정 | 이유 |
|---|---|---|
| 백엔드 Keep-Alive timeout | ALB idle timeout + 5초 이상 | Race condition 방지 |
| Health Check interval | 10~15초 | 빠른 상태 감지 |
| Healthy threshold | 2회 | 새 Target 빠른 투입 |
| Deregistration delay | 평균 요청 처리 시간 + 여유 | 진행 중 요청 완료 보장 |
| ECS minimum healthy % | 100% | 배포 중 가용 Target 보장 |
| ALB Access Log | 활성화 | 사후 분석 가능 |
| CloudWatch 알람 | HTTPCode_ELB_502_Count > 0 | 즉시 감지 |
ALB Access Log에는 클라이언트 IP, 요청 URL, User-Agent 등이 포함됩니다. S3 버킷에 적절한 접근 제어와 수명 주기 정책을 설정하여 로그 데이터를 보호해야 합니다.
7. 정리
- ALB 502는 ALB 자체 문제가 아니라 ALB↔백엔드 간 통신 실패를 의미합니다.
- 가장 흔한 원인은 모든 Target이 unhealthy인 경우이며, Health Check 설정을 먼저 확인합니다.
- 간헐적 502는 Keep-Alive timeout race condition이 원인인 경우가 많습니다. 백엔드 Keep-Alive를 ALB idle timeout보다 크게 설정합니다.
- 배포 중 502는 Health Check 전환 시간과 배포 전략의 조합으로 해결합니다.
- Access Log는 502 원인 분석의 핵심 도구입니다. 운영 환경에서는 반드시 활성화합니다.
참고 문서
'Troubleshooting' 카테고리의 다른 글
| EKS Pod가 외부 인터넷에 접근하지 못하는 경우 (0) | 2026.06.06 |
|---|---|
| Terraform Error acquiring the state lock 해결 방법 (0) | 2026.06.05 |
| Kubernetes CrashLoopBackOff 원인과 해결 방법 (0) | 2026.06.05 |
| S3 AccessDenied 원인과 해결 방법: Bucket Policy, IAM, KMS, VPC Endpoint까지 (0) | 2026.06.01 |
| Kubernetes ImagePullBackOff 원인과 해결 방법 (0) | 2026.06.01 |