
AWS Lambda 완전 정복: 함수 하나로 시작하는 서버리스 아키텍처
2014년 '함수 하나만 실행하는 서비스'로 시작해, 전 세계 수백만 개발자의 기본 도구가 된 Lambda. 탄생 배경부터 내부 작동 원리, MSA와의 관계, 실전 패턴과 비용 최적화까지 — Lambda를 제대로 이해하고 활용하는 완전 가이드.

2014년 '함수 하나만 실행하는 서비스'로 시작해, 전 세계 수백만 개발자의 기본 도구가 된 Lambda. 탄생 배경부터 내부 작동 원리, MSA와의 관계, 실전 패턴과 비용 최적화까지 — Lambda를 제대로 이해하고 활용하는 완전 가이드.
2014년 11월, AWS re:Invent. VP Werner Vogels가 무대에서 새 서비스를 발표했다. 이름은 Lambda. "코드를 업로드하면 이벤트에 반응하여 자동으로 실행된다. 서버 관리 불필요. 사용한 100밀리초 단위로만 과금."
발표 직후 개발자 커뮤니티의 반응은 반신반의였다. "그래서 이걸로 뭘 하라는 건데?" "장난감 아닌가?" "실무에서 쓸 수 있을까?"
10년이 지난 지금, Lambda는 AWS에서 가장 많이 사용되는 서비스 중 하나가 됐다. Datadog의 2024년 보고서에 따르면 AWS를 사용하는 조직의 70% 이상이 Lambda를 사용한다. 하루에 수조 건의 호출이 전 세계에서 처리된다.
"함수 하나만 실행하는 서비스"가 어떻게 이렇게 됐을까? 그리고 당신의 서비스에서는 Lambda를 어떻게 활용해야 할까?
Lambda의 탄생 배경을 이해하려면, 2013~2014년 AWS가 목격한 패턴을 알아야 한다.
수많은 AWS 고객이 동일한 아키텍처 패턴을 반복하고 있었다:
이 과정에서 EC2 인스턴스는 이미지가 업로드될 때만 일한다. 나머지 시간에는 놀고 있다. 그런데 이 "대기 → 이벤트 감지 → 처리 → 대기" 패턴을 위해 서버를 24시간 켜놓아야 했다.
Tim Wagner (Lambda의 GM)는 2014년 블로그에서 이렇게 설명했다:
"고객들이 EC2 위에서 반복적으로 구현하는 글루(glue) 코드가 있었다. 이벤트를 감지하고, 작은 작업을 수행하고, 결과를 다른 서비스에 전달하는 코드. 우리는 이 패턴 자체를 서비스로 만들기로 했다."
Lambda의 아이디어는 컴퓨터 과학의 오랜 개념에 뿌리를 두고 있다.
1936년 — 람다 대수(Lambda Calculus): 수학자 Alonzo Church가 개발한 함수 추상화 체계. "이름 없는 함수"로 연산을 표현하는 방법. AWS Lambda의 이름은 여기서 따왔다 — 입력을 받아 출력을 반환하는 순수 함수라는 개념.
1990~2000년대 — 이벤트 기반 아키텍처: Martin Fowler 등이 정리한 EDA(Event-Driven Architecture) 패턴. 시스템 간 통신을 직접 호출이 아닌 이벤트(메시지)로 하는 아키텍처. Lambda는 이 패턴을 클라우드에서 가장 쉽게 구현하는 방법이 됐다.
2014년 — AWS Lambda 출시: 이 두 아이디어의 결합. 순수 함수(입력 → 처리 → 출력) + 이벤트 트리거(이벤트가 오면 함수 실행) = FaaS.
Lambda에서 배포하는 단위는 함수(Function) 다. 하나의 함수는 하나의 작업을 수행한다.
# 가장 간단한 Lambda 함수
def lambda_handler(event, context):
name = event.get("name", "World")
return {
"statusCode": 200,
"body": f"Hello, {name}!"
}
event: 함수를 트리거한 이벤트 데이터 (HTTP 요청, S3 이벤트, SQS 메시지 등)context: 실행 환경 정보 (남은 시간, 메모리, 요청 ID)이 함수를 Lambda에 올리면, 누군가 HTTP 요청을 보내거나, S3에 파일을 올리거나, SQS에 메시지가 도착할 때마다 자동으로 실행된다.
이전 Fargate 글에서 소개한 Firecracker가 Lambda의 기반이기도 하다.
각 Lambda 함수 호출은 전용 Firecracker microVM 안에서 실행된다:
핵심 포인트: 실행 환경은 즉시 삭제되지 않고 "동결(freeze)" 된다. 같은 함수에 곧 다시 요청이 오면 동결된 환경을 "해동(thaw)" 하여 재사용한다. 이것이 웜 스타트(Warm Start) — 콜드 스타트 없이 밀리초 단위로 응답한다.
Lambda의 진짜 힘은 AWS의 거의 모든 서비스가 Lambda를 트리거할 수 있다는 것이다.
| 이벤트 소스 | 트리거 시점 | 대표적 사용 사례 |
|---|---|---|
| API Gateway | HTTP 요청 도착 | REST/GraphQL API 구현 |
| S3 | 파일 업로드/삭제 | 이미지 리사이징, 파일 처리 |
| DynamoDB Streams | DB 레코드 변경 | 변경 감지, 동기화, 알림 |
| SQS | 메시지 큐 도착 | 비동기 작업 처리 |
| EventBridge | 스케줄/이벤트 패턴 매칭 | 크론 작업, 이벤트 라우팅 |
| SNS | 알림 발행 | 팬아웃, 알림 처리 |
| Kinesis | 스트림 데이터 도착 | 실시간 데이터 처리 |
| CloudWatch Events | 리소스 상태 변경 | 인프라 자동화 |
| Cognito | 사용자 인증 이벤트 | 가입 후처리, 토큰 커스터마이징 |
| IoT Core | IoT 디바이스 메시지 | 센서 데이터 처리 |
모놀리식 아키텍처에서는 하나의 거대한 애플리케이션이 모든 기능을 포함한다. 사용자 인증, 주문 처리, 결제, 알림 — 모두 하나의 코드베이스, 하나의 배포 단위.
이 구조의 한계:
MSA(Microservices Architecture)는 이 문제를 서비스를 독립적인 작은 단위로 분리하여 해결한다. 각 서비스가 독립적으로 개발·배포·스케일링된다.
MSA를 구현하는 방법은 여러 가지다:
전통적 마이크로서비스는 도메인 단위로 분리한다: 주문 서비스, 결제 서비스, 사용자 서비스.
Lambda 기반 아키텍처는 이것을 더 잘게 쪼갠다: 기능(함수) 단위로 분리. 주문 생성 함수, 주문 검증 함수, 결제 요청 함수, 결제 확인 함수, 알림 발송 함수...
이 접근의 장점:
하지만 단점도 명확하다:
Lambda 기반 MSA에서 서비스 간 통신에는 두 가지 패턴이 있다:
1. 핸들러는 가볍게, 초기화는 밖에서
import boto3
# 핸들러 밖에서 초기화 → 웜 스타트 시 재사용
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("users")
def lambda_handler(event, context):
# 핸들러 안에서는 비즈니스 로직만
user_id = event["pathParameters"]["id"]
response = table.get_item(Key={"id": user_id})
return {
"statusCode": 200,
"body": json.dumps(response.get("Item", {}))
}
boto3.resource() 호출은 핸들러 밖에 둔다. 첫 번째 호출(콜드 스타트)에서만 실행되고, 이후 웜 스타트에서는 재사용된다. 이것만으로 응답 시간이 50~200ms 단축된다.
2. 함수는 한 가지 일만
하나의 Lambda 함수가 "이미지 리사이징 + 메타데이터 저장 + 알림 발송"을 모두 하면, 알림 서비스 장애가 이미지 처리까지 막는다. 각 작업을 별도 함수로 분리하고, 이벤트(SQS, EventBridge)로 연결한다.
3. 멱등성(Idempotency) 보장
Lambda는 최소 1회(at-least-once) 실행을 보장한다. 드물지만 같은 이벤트로 함수가 두 번 실행될 수 있다. 같은 요청이 두 번 와도 결과가 동일하도록 설계해야 한다.
# 나쁜 예: 중복 실행 시 잔액이 두 번 차감됨
balance -= amount
# 좋은 예: 트랜잭션 ID로 중복 확인
if not is_processed(transaction_id):
balance -= amount
mark_processed(transaction_id)
| 전략 | 효과 | 비용 |
|---|---|---|
| 경량 런타임 (Python, Node.js) | 콜드 스타트 100~300ms | 무료 |
| 패키지 크기 최소화 | 로드 시간 단축 | 무료 |
| Provisioned Concurrency | 콜드 스타트 제거 | 인스턴스 유지 비용 |
| SnapStart (Java) | 콜드 스타트 90% 단축 | 무료 |
| Lambda Layer로 공통 라이브러리 분리 | 배포 크기 감소 | 무료 |
| ARM64 (Graviton2) | 시작 시간 + 비용 동시 절감 | 무료 (오히려 20% 저렴) |
Lambda의 비용은 두 가지로 구성된다:
요청 수: 100만 건당 0.0000166667 (1ms 단위 과금)
실제 비용 시뮬레이션:
비용 최적화 핵심:
API Gateway가 HTTP 요청을 받아 Lambda로 전달하고, Lambda가 비즈니스 로직을 수행한 뒤 응답을 반환한다. 가장 기본적이고 가장 많이 쓰이는 패턴이다.
사용자가 프로필 사진 업로드
↓
S3에 원본 저장 → S3 이벤트 트리거
↓
Lambda A: 이미지 리사이징 (썸네일, 중간, 대형)
↓
리사이징된 이미지를 S3에 저장 → 완료 이벤트
↓
Lambda B: DynamoDB에 메타데이터 업데이트
↓
Lambda C: CloudFront 캐시 무효화
각 Lambda가 자신의 작업만 수행하고, 이벤트로 다음 단계를 트리거한다. 서버를 한 대도 관리하지 않는 완전한 이벤트 기반 파이프라인이다.
주문 처리처럼 순서가 중요한 작업에는 AWS Step Functions을 사용한다:
각 단계의 성공/실패/재시도/타임아웃을 Step Functions가 관리한다. Lambda 함수는 자기 로직에만 집중하면 된다.
EventBridge 스케줄러로 정기 작업을 실행한다:
EC2를 24시간 켜놓을 필요 없이, 실행되는 시간만 과금된다.
Kinesis 스트림 또는 DynamoDB Streams와 연동하여 실시간 데이터를 처리한다:
Netflix는 동영상 파일이 업로드되면 Lambda가 자동으로 여러 인코딩 작업을 트리거한다. 각 해상도(4K, 1080p, 720p)별 인코딩, 자막 처리, 메타데이터 추출 — 이 모든 것이 이벤트 기반으로 동작한다.
콘텐츠가 업로드되지 않는 시간에는 비용이 0이다. 새 시즌이 공개되어 대량 업로드가 발생하면 자동으로 수천 개의 Lambda가 병렬 실행된다.
이전 서버리스 글에서 언급한 사례를 더 구체적으로 보자. 전 세계 수백만 대의 자판기가 결제·재고 이벤트를 발생시키면:
이 전체 아키텍처에 EC2 인스턴스가 한 대도 없다.
디지털 미디어 회사 Bustle은 매달 10억 건 이상의 요청을 Lambda로 처리한다. EC2 기반에서 Lambda로 전환하면서:
2014년의 Lambda와 2026년의 Lambda는 사실상 다른 서비스다. 초기의 "60초 제한, Node.js만" 같은 제약은 대부분 해소됐다. 15분 실행 시간, 10GB 메모리, 컨테이너 이미지 지원 — 이제 Lambda로 할 수 없는 것은 거의 없다.
모든 도구에는 한계가 있다. Lambda가 최선이 아닌 경우:
| 상황 | 이유 | 대안 |
|---|---|---|
| 15분 이상 실행 | Lambda 시간 제한 | Fargate, ECS |
| GPU 필요 (AI 학습) | Lambda GPU 미지원 | EC2 P/G 인스턴스, SageMaker |
| WebSocket 장시간 연결 | Lambda는 요청-응답 모델 | ECS, AppRunner |
| 초당 수만 건의 상시 트래픽 | 비용이 EC2보다 높아짐 | ECS + EC2 |
| 복잡한 로컬 개발/디버깅 | 서버리스 환경 재현 어려움 | SAM Local, LocalStack |
Lambda의 본질은 이렇다:
"문제를 함수 하나의 크기로 쪼개고, 이벤트에 반응하여 자동으로 실행되게 하는 것."
이것은 단순한 기술 선택이 아니라 사고방식의 전환이다. "어떤 서버에서 실행할까?"가 아니라 "어떤 이벤트에 반응해야 할까?"를 먼저 생각하는 것. "서버를 몇 대 준비할까?"가 아니라 "함수가 얼마나 빨리 응답해야 할까?"를 고민하는 것.
Alonzo Church의 람다 대수가 "이름 없는 함수"로 계산을 추상화했듯, AWS Lambda는 "서버 없는 함수"로 인프라를 추상화했다. 이름의 선택은 우연이 아니었다.
코어닷투데이의 AI 서비스에서도 Lambda는 곳곳에서 활용된다. 이미지 전처리, 이벤트 기반 알림, 데이터 파이프라인, API 엔드포인트 — 각각의 작업이 함수 하나의 크기로 정의되고, 필요할 때만 실행되며, 완료되면 사라진다. 인프라가 보이지 않는 곳에서, 문제 해결이 함수 단위로 일어나고 있다.