목차
- 문제 정의 — 간헐적 트래픽에 맞는 인프라
- 기존 접근의 한계 — EC2와 컨테이너는 왜 무거운가
- Lambda + API Gateway 연동의 핵심 흐름
- CORS 오류, 진짜 원인은 어디인가
- 커스텀 도메인 연결 — 단계가 길어 보이지만 본질은 단순하다
- 성능과 비용 검증 — 콜드 스타트 실측
- 실무에서 자주 놓치는 한계점
- 언제 쓰고, 언제 안 쓰나
AWS Lambda API Gateway 연동은 서버 인스턴스를 띄우지 않고 HTTP 요청을 처리하는 가장 짧은 경로다. Lambda는 함수 단위 실행 환경이고, API Gateway는 HTTP 요청을 Lambda 호출로 변환하는 프록시 역할을 한다. 두 서비스를 묶으면 24시간 떠있는 서버 없이도 REST API를 운영할 수 있다.
게다가, 문제는 이 조합이 만능이 아니라는 점이다. 콜드 스타트, CORS 헤더의 책임 분리, 커스텀 도메인 연결의 다단계 인증서 발급까지 실무에서 막히는 지점이 분명히 존재한다. 이 글은 프론트엔드에서 백엔드로 넘어온 입장에서 Express 기반 EC2 구성과 비교해, 어디서 비용이 줄고 어디서 복잡도가 늘어나는지 정리한다.
문제 정의 — 간헐적 트래픽에 맞는 인프라
간헐적으로 호출되는 내부 API, 웹훅 수신기, 소규모 SaaS 백엔드는 EC2를 띄울 만큼의 워크로드가 아니다. t3.small을 한 달 켜두면 약 USD 15가 청구된다(2026년 6월 기준 us-east-1 온디맨드). 하루 평균 호출이 500건 정도라면 인스턴스가 놀고 있는 시간이 99%를 넘는다.
게다가, 컨테이너 기반 ECS Fargate는 더 유연하지만, Task 정의·VPC·ALB·Target Group을 묶어야 한다. 익숙해지면 강력하지만, 첫 진입에서 학습량이 만만치 않다. (프론트엔드 출신 입장에서 가장 당황스러운 지점이 ALB 헬스체크 경로 디버깅이었다.)
또한, Lambda + API Gateway는 이 구간을 좁힌다. 함수 코드와 라우팅 매핑 두 가지만 정의하면, 호출이 들어올 때만 컴퓨팅 자원을 점유한다. 호출 100만 건이 무료 티어로 제공되고, 그 이후는 호출당 USD 0.0000002 수준으로 과금된다(공식 가격 페이지, 2026년 6월 기준).
기존 접근의 한계 — EC2와 컨테이너는 왜 무거운가
웹서버를 항상 띄워두는 모델은 두 가지 비용을 끌고 다닌다.
따라서, 첫째, 유휴 시간의 컴퓨팅 비용. 둘째, 운영 책임. OS 패치, 로그 로테이션, 보안 그룹 갱신, 인스턴스 재시작 시나리오까지 누군가 책임져야 한다. 작은 팀에서는 이게 코드 작성보다 더 많은 시간을 잡아먹는다.
물론, ECS Fargate가 운영 부담은 줄여주지만, 라우팅 계층(ALB)과 네트워킹(VPC, NAT Gateway)까지 묶이면 월 USD 30 안팎이 고정으로 빠진다. NAT Gateway 하나만 해도 시간당 USD 0.045다. 트래픽이 적은 서비스에 NAT를 붙이면 데이터 처리 비용보다 게이트웨이 가동 비용이 더 크다.
따라서, 이 지점에서 서버리스가 의미를 가진다. 트래픽이 0이면 청구액도 0에 수렴한다. 다만 모든 워크로드에 맞는 모델은 아니다. 이 부분은 마지막 섹션에서 다시 다룬다.
Lambda + API Gateway 연동의 핵심 흐름
반면, 배포 구조는 크게 두 레이어로 나뉜다. Lambda 함수 자체와, API Gateway 라우팅 매핑이다.
Lambda 함수 정의
물론, 런타임은 Node.js 20.x 또는 Python 3.12를 권장한다. 두 런타임 모두 초기화 시간이 짧고, AWS SDK v3가 기본 포함된다. 코드 패키지는 zip 또는 컨테이너 이미지로 업로드한다.
// handler.js — Node.js 20.x
export const handler = async (event) => {
// API Gateway HTTP API는 event.requestContext.http.method로 메서드 확인
const method = event.requestContext.http.method;
const path = event.rawPath;
if (method === "GET" && path === "/health") {
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ status: "ok" }),
};
}
return { statusCode: 404, body: "Not Found" };
};
결국, 응답은 statusCode, headers, body를 키로 가진 객체를 반환해야 한다. body는 반드시 문자열이어야 한다. 객체를 그대로 넘기면 API Gateway가 500을 응답한다. 처음 작성할 때 가장 자주 막히는 부분이 이 직렬화 누락이다.
API Gateway 라우팅 매핑
또한, REST API와 HTTP API 두 종류가 있다. 새 프로젝트라면 HTTP API가 기본 선택이다. 비용이 약 70% 저렴하고(REST: USD 3.5/백만 호출, HTTP: USD 1.0/백만 호출, 2026년 6월 us-east-1 기준), 지연 시간도 평균 60ms 정도 낮은 것으로 보고된다(AWS 공식 비교 문서).
AWS CLI로 배포하는 가장 짧은 경로는 이렇다.
# Lambda 함수 생성 (zip 업로드)
aws lambda create-function \
--function-name myapi-handler \
--runtime nodejs20.x \
--role arn:aws:iam::123456789012:role/lambda-basic-role \
--handler handler.handler \
--zip-file fileb://function.zip
# HTTP API 생성
aws apigatewayv2 create-api \
--name myapi \
--protocol-type HTTP \
--target arn:aws:lambda:us-east-1:123456789012:function:myapi-handler
# Lambda에 호출 권한 부여 (자주 빠뜨리는 단계)
aws lambda add-permission \
--function-name myapi-handler \
--statement-id apigw-invoke \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com
마지막 add-permission 단계가 핵심이다. 이걸 빠뜨리면 호출 시 {"message":"Internal Server Error"}만 떨어지고 CloudWatch에 함수 호출 로그가 남지 않는다. 콘솔로 생성하면 자동 적용되지만, CLI나 IaC 도구로 만들 때는 명시해야 한다.
CORS 오류, 진짜 원인은 어디인가
서버리스 REST API를 만들면 거의 반드시 한 번은 마주치는 게 CORS다. 프론트엔드에서 fetch를 날리면 브라우저 콘솔에 이 메시지가 뜬다.
Access to fetch at 'https://abc123.execute-api.us-east-1.amazonaws.com/users'
from origin 'https://app.example.com' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
반면, 가장 흔한 시행착오는 Lambda 핸들러에 Access-Control-Allow-Origin 헤더를 추가하면 해결될 거라고 가정하는 경우다. 절반은 맞다. GET, POST 같은 단순 요청에서는 Lambda 응답 헤더로 처리된다. 다만 Content-Type이 application/json인 POST는 브라우저가 OPTIONS preflight를 먼저 보내고, 이 OPTIONS 요청은 Lambda까지 도달하지 않을 수 있다.
HTTP API에서는 API Gateway 레벨에서 CORS를 설정해야 preflight가 통과한다.
aws apigatewayv2 update-api \
--api-id abc123def \
--cors-configuration \
AllowOrigins=https://app.example.com,\
AllowMethods=GET,POST,PUT,DELETE,OPTIONS,\
AllowHeaders=Content-Type,Authorization,\
MaxAge=300
CORS 책임은 두 레이어로 나뉜다. preflight(OPTIONS)는 API Gateway가, 실제 응답 헤더는 Lambda가 책임진다. 둘 중 하나만 설정하면 절반의 요청만 통과한다. 프론트엔드에서 백엔드로 넘어온 입장에서는 이 분리 지점이 가장 비직관적인 부분이다.
특히, :::tip
AllowOrigins에 *를 쓸 거면 AllowCredentials=true와 함께 쓸 수 없다(W3C Fetch 명세 규칙). 자격 증명을 포함하는 요청을 허용하려면 정확한 출처를 명시해야 한다. CloudFront 뒤에 두는 경우 캐시 키에 Origin 헤더를 포함시켜야 origin별로 다른 응답이 캐싱된다.
:::
커스텀 도메인 연결 — 단계가 길어 보이지만 본질은 단순하다
기본 엔드포인트 https://abc123.execute-api.us-east-1.amazonaws.com는 외부 공개용으로 쓰기 어색하다. api.example.com 같은 도메인을 붙이는 흐름은 네 단계다.
| 단계 | 작업 | 도구 | 평균 소요 |
|---|---|---|---|
| 1 | SSL 인증서 발급 | AWS Certificate Manager | 5~30분 |
| 2 | API Gateway 커스텀 도메인 생성 | apigatewayv2 | 즉시 |
| 3 | API Mapping 연결 | apigatewayv2 | 즉시 |
| 4 | Route53 A 레코드(Alias) 추가 | Route53 | DNS 전파 ~5분 |
예를 들어, ACM 인증서는 API Gateway가 위치한 리전에 발급해야 한다. CloudFront용 인증서가 us-east-1 고정이라는 점과 혼동하기 쉽다. HTTP API의 Regional 엔드포인트는 해당 리전 인증서를 요구한다.
# 커스텀 도메인 생성
aws apigatewayv2 create-domain-name \
--domain-name api.example.com \
--domain-name-configurations \
CertificateArn=arn:aws:acm:us-east-1:123456789012:certificate/xxx
# API와 도메인 매핑
aws apigatewayv2 create-api-mapping \
--domain-name api.example.com \
--api-id abc123def \
--stage '$default'
마지막 Route53 단계에서 A 레코드 타입을 Alias로 설정해야 한다. CNAME으로 잡으면 루트 도메인(example.com 같은 zone apex)에서는 동작하지 않는다. Alias는 AWS 내부 라우팅이라 추가 비용이 없다.
성능과 비용 검증 — 콜드 스타트 실측
서버리스의 가장 큰 약점으로 꼽히는 콜드 스타트는 실제로 얼마나 느릴까. Lambda Power Tuning 도구로 측정한 공식 가이드(GitHub: alexcasalboni/aws-lambda-power-tuning) 기준 수치다.
| 런타임 | 메모리 | 콜드 스타트 평균 | 웜 호출 평균 |
|---|---|---|---|
| Node.js 20.x | 128MB | 약 180~250ms | 5~15ms |
| Node.js 20.x | 512MB | 약 90~140ms | 3~10ms |
| Python 3.12 | 128MB | 약 200~300ms | 8~20ms |
| Java 21 (SnapStart) | 1024MB | 약 300~500ms | 10~25ms |
콜드 스타트를 줄이는 가장 단순한 방법은 메모리 할당량을 올리는 것이다. Lambda는 메모리에 비례해서 CPU 할당량도 함께 올라간다. 128MB로 시작하지 말고 512MB 이상으로 잡으면 초기화 시간이 절반 가까이 줄어든다. 비용은 두 배가 되지만 호출 시간이 짧아져 실제 청구액 증가는 그보다 적은 경향이 있다.
자주 호출되지 않는 함수에 Provisioned Concurrency를 붙이는 건 권장하지 않는다. 시간당 USD 0.0000041316/MB로 항상 과금되기 때문이다(공식 가격, 2026년 6월). 차라리 EventBridge 스케줄로 5분마다 한 번씩 웜업 호출을 보내는 편이 저렴하다.
# 5분마다 함수 웜업
aws events put-rule \
--name keep-lambda-warm \
--schedule-expression "rate(5 minutes)"
aws events put-targets \
--rule keep-lambda-warm \
--targets "Id"="1","Arn"="arn:aws:lambda:us-east-1:123456789012:function:myapi-handler"
실제로, 체감상 5분 간격의 웜업으로 콜드 스타트를 상당 부분 피할 수 있다. 수치는 동시성 패턴에 따라 달라지므로 실측이 필요하다.
실무에서 자주 놓치는 한계점
그러나, 여기까지 흐름을 따라가면 동작은 한다. 그러나 운영 단계에서 부딪히는 한계가 분명히 존재한다.
동기 응답 시간 29초 제한
API Gateway는 통합 응답에 최대 29초의 타임아웃을 강제한다(공식 문서, REST/HTTP API 공통 적용). LLM 호출, 외부 API 체이닝, 무거운 PDF 변환 같은 작업은 이 한도를 넘기 쉽다. 비동기 처리가 필요하면 SQS나 Step Functions로 우회해야 한다.
페이로드 10MB 제한
이처럼, 요청과 응답 본문이 각각 10MB로 묶여 있다. 큰 파일 업로드는 S3 Presigned URL로 우회한다. 이 패턴이 서버리스에서는 거의 표준이다.
VPC 접근 시 콜드 스타트 증가
결국, RDS나 ElastiCache처럼 VPC 내부 리소스에 접근하려면 Lambda를 VPC에 연결해야 한다. Hyperplane ENI 도입 이후 많이 개선됐지만 콜드 스타트에 100~200ms가 추가될 수 있다는 보고가 있다(AWS 공식 블로그, 2025년 업데이트 기준).
언제 쓰고, 언제 안 쓰나
그런데, Lambda + API Gateway 연동이 맞는 상황과 맞지 않는 상황의 기준은 비교적 분명하다.
따라서, 적합한 상황
- 트래픽이 간헐적이고 예측 불가능한 내부 도구 API
- 웹훅 수신기, 이벤트 처리기
- 프로토타입 또는 MVP 단계의 백엔드
- 월 호출 100만 건 이하 또는 일 호출 10만 건 이하 규모의 SaaS API
한편, 부적합한 상황
- 호출당 처리 시간이 30초 이상인 워크로드
- 초당 수천 건 이상의 일정한 트래픽 — 이 구간부터 ECS 또는 EKS가 단가에서 우위
- 강한 일관성과 영구 연결이 필요한 WebSocket 기반 실시간 채팅(API Gateway WebSocket이 별도로 있지만 영역이 다르다)
- 마이크로초 단위 지연이 요구되는 트레이딩 등 저지연 API
그러나, 당장 실행할 수 있는 액션을 셋으로 좁히면 이렇다. 첫째, 새 프로젝트라면 HTTP API로 시작하라. REST API 대비 비용이 70% 저렴하고 설정이 단순하다. 둘째, CORS는 API Gateway 레이어에서 먼저 설정하라. Lambda 응답 헤더만으로는 preflight가 통과하지 않는다. 셋째, 콜드 스타트가 신경 쓰이면 Provisioned Concurrency보다 EventBridge 웜업을 먼저 시도하라. 비용 차이가 크다.
참고 자료
- AWS Lambda 공식 가격 페이지
- API Gateway HTTP API와 REST API 비교 문서
- alexcasalboni/aws-lambda-power-tuning (GitHub)
관련 글
- AWS EC2 Auto Scaling 설정 — Target Tracking·Step Scaling 비교와 알람 연동 – 트래픽 급증에 ASG가 늦게 반응하는 원인은 정책 선택만의 문제가 아니다. 워밍업, 알람 평가 시간, 스케일인 보호까지 묶어서 살펴본다.
- AWS S3 정적 웹사이트 배포 – CloudFront, HTTPS, 자동 배포 실전 – AWS S3 정적 웹사이트 배포는 버킷 켜는 것으로 끝나지 않는다. CloudFront OAC, us-east-1 인증서, 캐시 무효화 세…
- AWS RDS 슬로우 쿼리 튜닝 — Performance Insights·슬로우 쿼리 로그 비교 – AWS RDS 슬로우 쿼리 튜닝을 시작할 때 후보 도구가 셋이었다. Performance Insights, 슬로우 쿼리 로그+pt-quer…