운영, 보안, 비용
Lambda 타임아웃 해결 (Task timed out 의 원인 찾기)
"Task timed out after N seconds" 가 나올 때 VPC 안 Lambda 의 외부 호출, 느린 다운스트림, 연결 재사용 실패, 콜드 스타트와 INIT 단계, 메모리 부족에 따른 CPU 부족, API Gateway 와 SQS 의 시간 한도 불일치를 구분하는 방법과 해결책을 증상, 원인, 해결 순서로 정리합니다.
Lambda타임아웃콜드 스타트VPC트러블슈팅2026-10 기준, 약 6분
증상
CloudWatch Logs 에 이런 줄이 남습니다.
REPORT RequestId: 3f1c... Duration: 30000.00 ms Billed Duration: 30000 ms Memory Size: 512 MB Max Memory Used: 498 MB
2026-10-20T09:14:03.120Z 3f1c... Task timed out after 30.00 seconds또는 호출하는 쪽에서 다른 모양으로 보입니다.
| 호출 경로 | 보이는 증상 |
|---|---|
| API Gateway REST API | 클라이언트는 504 와 Endpoint request timed out, 함수는 계속 실행 중일 수 있음 |
| ALB | 502 또는 504 |
| SQS 이벤트 소스 | 같은 메시지가 여러 번 처리됨, DLQ 로 이동 |
| Step Functions | States.Timeout 또는 Lambda.Unknown |
REPORT 줄의 Duration 이 설정한 제한 시간과 같고 Max Memory Used 가 메모리 크기에 거의 닿았다면 메모리 부족을 함께 의심합니다.
원인
| 원인 | 단서 |
|---|---|
| VPC 에 연결된 함수가 인터넷이나 AWS API 로 나갈 길이 없음 | 외부 호출에서 정확히 제한 시간까지 멈춤. NAT, 엔드포인트 없음 |
| 다운스트림(DB, 외부 API)이 느림 | X-Ray 추적에서 특정 하위 구간이 김 |
| SDK, HTTP 클라이언트의 제한 시간이 함수보다 김 | 재시도가 쌓여 함수 제한 시간을 넘김 |
| 연결을 핸들러 안에서 매번 새로 엶 | 호출마다 TLS, DB 연결 수립 시간 |
| 메모리가 작아 CPU 가 부족 | 메모리를 늘리면 시간이 크게 줄어듦 |
| 콜드 스타트의 INIT 단계가 김 | Init Duration 이 큼, 첫 요청만 느림 |
| 호출자 한도가 함수보다 짧음 | API Gateway 통합 제한 시간 기본 29 초 |
| 처리량 대비 배치가 큼 | SQS, Kinesis 배치 하나 처리가 오래 걸림 |
해결
1. 어디서 시간을 쓰는지 측정
X-Ray 추적(또는 Application Signals, OpenTelemetry)을 켜면 SDK 호출, HTTP 호출 구간이 나뉘어 보입니다. 우선 Logs Insights 로 분포를 봅니다.
filter @type = "REPORT"
| stats count(*) as calls, pct(@duration, 50) as p50, pct(@duration, 99) as p99,
max(@maxMemoryUsed / @memorySize * 100) as memPct, count(@initDuration) as coldStarts
by bin(1h)2. VPC 함수의 나가는 길 확인
VPC 에 연결된 Lambda 는 퍼블릭 IP 를 받지 않습니다. 퍼블릭 서브넷에 붙여도 인터넷에 못 나갑니다.
- 외부 API 가 필요하면 프라이빗 서브넷에 붙이고 그 서브넷의 기본 경로를 NAT Gateway 로 보냅니다.
- S3, DynamoDB, Secrets Manager, SQS 같은 AWS 서비스만 부른다면 VPC 엔드포인트를 만듭니다. 절차는 EC2 가 인터넷에 못 나갈 때 와 같습니다.
- DB 접속만 필요하고 VPC 가 꼭 필요하지 않다면 VPC 연결을 다시 검토합니다.
3. 제한 시간을 계층별로 맞추기
바깥쪽이 안쪽보다 항상 길어야 합니다.
| 계층 | 권장 |
|---|---|
| HTTP, SDK 클라이언트 | 함수 남은 시간보다 짧게. 재시도 포함 총 시간 계산 |
| Lambda 함수 | 정상 p99 의 2~3 배, 최대 900 초 |
| API Gateway 통합 | 기본 29 초. 더 길면 비동기 패턴(작업 ID 반환 후 조회)으로 |
| SQS 가시성 제한 시간 | 함수 제한 시간의 6 배 이상 (AWS 권장) |
import boto3, botocore
cfg = botocore.config.Config(connect_timeout=2, read_timeout=5, retries={"max_attempts": 3, "mode": "standard"})
ddb = boto3.client("dynamodb", config=cfg) # 핸들러 밖에서 만들어 재사용
def handler(event, context):
if context.get_remaining_time_in_millis() < 3000:
raise RuntimeError("남은 시간이 부족해 다음 재시도로 넘깁니다")
...4. 연결 재사용과 메모리 조정
- SDK 클라이언트, DB 연결 풀은 핸들러 밖(초기화 코드)에서 만들어 다음 호출에서 재사용합니다.
- RDS 에 연결하면 RDS Proxy 로 연결 폭주와 연결 수립 지연을 줄입니다.
- Lambda 는 메모리에 비례해 CPU 를 줍니다. 메모리를 512 MB 에서 1,024 MB 로 올렸을 때 시간이 절반이 되면 비용은 거의 같고 지연은 줄어듭니다. AWS Lambda Power Tuning 으로 최적점을 찾습니다.
5. 콜드 스타트 줄이기
- 2025-08-01 부터 INIT 단계도 과금되므로 초기화가 긴 함수는 비용 면에서도 손해입니다.
- 패키지 크기를 줄이고, 무거운 라이브러리는 필요한 곳에서만 불러옵니다.
- Java, Python, .NET 은 SnapStart 로 초기화된 스냅숏에서 시작합니다.
- 지연에 민감한 경로는 프로비저닝된 동시성으로 미리 데워 둡니다.
6. 15 분을 넘는 일이라면
Lambda 한 번의 실행은 최대 15 분입니다. 이보다 긴 일을 제한 시간만 늘려서 해결하려 하지 않습니다.
- 단계를 나눠 Step Functions 로 엮습니다.
- re:Invent 2025 에 나온 Lambda Durable Functions 는 함수 실행을 체크포인트로 나눠 기다리는 동안 과금 없이 일시 중지했다가 이어서 실행합니다(최대 1 년). 단계가 많은 주문 처리, 승인 대기 흐름에 맞습니다.
- 계속 도는 무거운 처리는 ECS on Fargate 나 Lambda Managed Instances 를 검토합니다.
재발 방지
Durationp99 가 제한 시간의 80% 를 넘으면 울리는 CloudWatch 경보를 겁니다.- 함수마다 실패 대상(SQS DLQ, 실패 시 대상)을 설정해 시간 초과된 이벤트를 잃지 않게 합니다.
- 처리 로직을 멱등하게 만들어 재시도로 두 번 실행돼도 안전하게 합니다.