AWS Lambda 504 Gateway Timeout 에러 완벽 해결: 비동기(Async) 아키텍처 전환

AWS Lambda 504 Gateway Timeout 에러 완벽 해결: 비동기 아키텍처 전환

"API Gateway에 Lambda를 붙여 대용량 엑셀 다운로드 API를 만들었는데, 데이터가 조금만 커져도 브라우저에 504 Gateway Timeout 에러가 떨어지며 서버가 뻗어버립니다."

서버리스(Serverless) 환경을 처음 도입한 백엔드 개발자들이 가장 뼈아프게 마주하는 인프라 장벽입니다. 클라우드는 마법이 아닙니다. 트래픽이 몰리면 알아서 확장(Scale-out)되지만, 플랫폼이 강제하는 '시간의 제약'을 이해하지 못하면 서비스는 언제든 멈출 수 있습니다.

초보자들은 이 에러를 보면 단순히 Lambda의 타임아웃 설정을 15분으로 늘리는 미봉책을 씁니다. 하지만 근본적인 문제는 해결되지 않습니다. 본 가이드에서는 504 에러를 유발하는 AWS 네트워크의 물리적 제약을 해체하고, 메시지 큐(Message Queue)를 활용한 비동기 아키텍처 설계 노하우를 단호하게 제시합니다.

📌 이 글의 핵심 포인트

  • API Gateway의 29초 하드 리미트(Hard Limit)와 Lambda 타임아웃의 엇갈린 관계 이해
  • 동기식(Synchronous) 처리의 한계와 트래픽 폭주 시 발생하는 병목 현상 분석
  • AWS SQS를 활용한 이벤트 기반 비동기(Asynchronous) 파이프라인 구축법

1단계: 에러의 본질 - 29초의 절대 방어막

504 Gateway Timeout 에러는 Lambda의 잘못이 아닙니다. 유저의 요청을 받아 Lambda로 전달하는 앞단의 API Gateway가 뱉어내는 에러입니다. API Gateway(REST API 기준)는 백엔드 통합의 최대 응답 대기 시간을 29초로 엄격하게 제한하고 있습니다. 이는 AWS 측에 요청해도 절대 늘려주지 않는 하드 리미트(Hard Limit)입니다.

Lambda의 타임아웃을 5분으로 늘려봤자, 29초가 넘어가는 순간 API Gateway는 유저에게 504 에러를 던지고 연결을 끊어버립니다. 유저는 에러 화면을 보게 되고, Lambda는 백그라운드에서 홀로 5분 동안 연산을 계속하며 클라우드 비용만 갉아먹는 최악의 상태에 빠집니다.

2단계: 완벽한 트러블슈팅 - SQS 기반 비동기 아키텍처

30초 이상 걸리는 무거운 연산(대규모 DB 조회, 외부 API 호출, 파일 생성 등)은 클라이언트가 응답을 기다리게 하는 동기식으로 설계하면 안 됩니다. 요청을 받으면 즉시 접수 완료 신호를 보내고, 실제 작업은 백그라운드에서 처리하는 구조로 전환해야 합니다.

이때 중간에 버퍼 역할을 해줄 AWS SQS(Simple Queue Service)를 도입합니다. 첫 번째 Lambda(API용)는 유저의 요청을 받아 SQS에 메시지를 던진 후 즉시 202 Accepted를 반환합니다. 그리고 두 번째 Lambda(워커용)가 SQS에서 메시지를 꺼내와 15분 동안 느긋하게 무거운 작업을 처리하는 구조입니다.

// 1. API를 처리하는 프론트 람다 (SQS에 메시지만 던지고 즉시 종료)
const { SQSClient, SendMessageCommand } = require("@aws-sdk/client-sqs");
const sqs = new SQSClient({ region: "ap-northeast-2" });

exports.handler = async (event) => {
    // SQS 대기열로 작업 내용 전송
    await sqs.send(new SendMessageCommand({
        QueueUrl: process.env.QUEUE_URL,
        MessageBody: JSON.stringify({ userId: 123, action: "export_excel" })
    }));
    
    // 29초 제한에 걸리기 전(약 0.1초 만에) 202 상태 코드로 즉시 응답
    return {
        statusCode: 202,
        body: JSON.stringify({ message: "요청이 접수되었습니다. 완료 시 알림을 드립니다." })
    };
};

🙋‍♂️ 자주 묻는 질문 (FAQ)

Q. 클라이언트는 작업이 끝난 걸 어떻게 알 수 있나요?
A. 비동기 처리 완료 후 클라이언트에게 결과를 알려주기 위해 웹소켓(WebSocket)으로 푸시 알림을 보내거나, 프론트엔드에서 주기적으로 작업 상태 API를 찔러보는 폴링(Polling) 방식을 구현해야 합니다.

Q. HTTP API나 WebSocket API를 쓰면 타임아웃이 다른가요?
A. 네, HTTP API는 30초 제한이지만, WebSocket API는 유휴 상태 타임아웃이 10분, 최대 연결 시간이 2시간이므로 장시간 지속되는 작업에 훨씬 유리한 대안이 될 수 있습니다.

💡 핵심 정리 및 마무리

서버리스 아키텍처에서 발생하는 504 타임아웃은 코드의 논리적 오류가 아니라 인프라 아키텍처의 설계 결함입니다. 무조건 기다리는 방식을 버리고, SQS를 활용한 이벤트 기반의 비동기 파이프라인을 구축하여 유연하고 확장성 있는 시스템을 설계하시기 바랍니다.

댓글

이 블로그의 인기 게시물

Zapier & Make.com 자동화의 덫: 무한 루프(Infinite Loop) 에러 완벽 방어 아키텍처

엑셀 보고서의 종말: 구글 스프레드시트와 루커 스튜디오(Looker Studio)로 실시간 대시보드 구축하기

Docker OOMKilled (Exit Code 137) 에러의 진실: 컨테이너 메모 누수 방어 및 리소스 최적화 아키텍처