SAABlog
컴퓨팅중급

Lambda 함수 최적화: 콜드스타트 해결부터 메모리 튜닝까지

AWS Lambda 함수의 성능을 최적화하는 방법을 설명합니다. 콜드스타트 해결, 메모리-CPU 관계, Provisioned Concurrency까지 완벽 가이드입니다.

PHILOLAMB-
Lambda서버리스콜드스타트최적화성능

관련 시험 도메인

  • Design High-Performing Architectures
  • Design Cost-Optimized Architectures

핵심 요약

Lambda 최적화의 핵심: 메모리를 늘리면 CPU도 증가하고, 콜드스타트는 Provisioned Concurrency나 SnapStart로 해결합니다. 핸들러 외부에서 초기화하고 /tmp에 캐싱하면 실행 시간을 줄일 수 있습니다.

시험 팁

시험 빈출: "Lambda 콜드스타트를 줄이려면?" → Provisioned Concurrency 또는 SnapStart(Java). "Lambda 성능을 높이려면?" → 메모리 증가 (CPU도 함께 증가).


1. Lambda 실행 환경 이해

실행 환경 수명 주기

┌─────────────────────────────────────────────────────────┐
│              Lambda 실행 환경 수명 주기                    │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  [첫 번째 호출 - 콜드스타트]                               │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐          │
│  │ 환경 생성 │ → │ Init 단계│ → │ Invoke   │           │
│  │ (다운로드)│    │(초기화)  │    │(핸들러)  │           │
│  └──────────┘    └──────────┘    └──────────┘          │
│      콜드스타트 지연 시간       │  실제 실행 시간         │
│  ─────────────────────────────┼───────────────          │
│                                                         │
│  [후속 호출 - 웜스타트]                                   │
│  ┌──────────────────────────┐    ┌──────────┐          │
│  │   환경 재사용 (스킵)      │ → │ Invoke   │           │
│  └──────────────────────────┘    └──────────┘          │
│           빠름!                   실제 실행 시간         │
└─────────────────────────────────────────────────────────┘

콜드스타트란?

콜드스타트는 Lambda가 새로운 실행 환경을 생성하는 과정에서 발생하는 지연입니다:

  1. 코드 다운로드
  2. 런타임 환경 시작
  3. Init 코드 실행 (핸들러 외부 코드)
런타임평균 콜드스타트 시간
Python~200ms
Node.js~200ms
Go~100ms
Java~1-3초
.NET~500ms-1초

2. 메모리와 CPU의 관계

핵심 개념

Lambda에서 메모리를 늘리면 CPU도 비례하여 증가합니다. 이는 Lambda의 가장 중요한 특징입니다.

┌─────────────────────────────────────────────────────────┐
│              메모리-CPU 비례 관계                          │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   메모리          CPU 성능          vCPU               │
│   ───────────────────────────────────────────           │
│   128 MB          낮음              ~0.1 vCPU           │
│   512 MB          중간              ~0.4 vCPU           │
│   1,792 MB        1 vCPU            1 vCPU              │
│   3,008 MB        1.7 vCPU          ~2 vCPU             │
│   10,240 MB       6 vCPU            6 vCPU (최대)       │
│                                                         │
│   1,769MB 이상: 멀티스레드 병렬 처리 가능                  │
└─────────────────────────────────────────────────────────┘

메모리 튜닝 전략

비용 최적화 공식:
실행 시간 × 메모리 = 비용

예시:
- 128MB × 10초 = 1,280 MB-초
- 512MB × 2.5초 = 1,280 MB-초 (동일 비용, 더 빠름!)

메모리를 늘려도 실행 시간이 비례해 줄어들면
비용은 같거나 오히려 줄어들 수 있음

AWS Lambda Power Tuning

메모리 최적화를 자동으로 테스트하는 도구입니다:

# Step Functions로 다양한 메모리 설정 테스트
# 128MB ~ 10GB까지 모든 조합 테스트 가능
# 결과: 최적의 메모리 설정 추천

일반적인 결과:
- 6GB 이상에서는 성능 개선 폭이 감소
- 비용 대비 성능 곡선의 "스위트 스팟" 찾기

시험 팁

시험 포인트: Lambda 함수가 CPU 집약적이라면 메모리를 늘려 CPU를 증가시켜야 합니다. 메모리와 CPU는 비례합니다.


3. 콜드스타트 해결 방법

방법 1: Provisioned Concurrency

미리 실행 환경을 준비해두어 콜드스타트를 완전히 제거합니다.

┌─────────────────────────────────────────────────────────┐
│              Provisioned Concurrency                     │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   설정: Provisioned Concurrency = 100                   │
│                                                         │
│   ┌────┐ ┌────┐ ┌────┐ ┌────┐ ... ┌────┐              │
│   │ 환경 │ │ 환경 │ │ 환경 │ │ 환경 │     │ 환경 │              │
│   │ 1   │ │ 2   │ │ 3   │ │ 4   │     │100 │              │
│   └────┘ └────┘ └────┘ └────┘     └────┘              │
│        ↑                                                │
│   미리 초기화되어 대기 중 (웜 상태 유지)                   │
│                                                         │
│   요청 → 즉시 응답 (콜드스타트 없음)                      │
└─────────────────────────────────────────────────────────┘

비용 고려사항:

예: 1,536MB 메모리, 100개 동시성, 24시간
= 약 $54/일 = 약 $1,620/월

주의: EC2처럼 지속 비용 발생
→ 트래픽 패턴에 따라 Auto Scaling 설정 권장

방법 2: Lambda SnapStart (Java)

Java 함수의 Init 단계 스냅샷을 저장하여 콜드스타트를 최대 90% 단축합니다.

┌─────────────────────────────────────────────────────────┐
│                  SnapStart 작동 방식                      │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  [버전 배포 시]                                          │
│  Init 실행 → 메모리 상태 스냅샷 → 암호화 저장            │
│                                                         │
│  [함수 호출 시]                                          │
│  스냅샷 로드 → 즉시 실행 (Init 스킵)                     │
│                                                         │
│  결과: Java 콜드스타트 1-3초 → 200ms 이하                │
└─────────────────────────────────────────────────────────┘

방법 3: EventBridge 워밍업

5분마다 Lambda를 주기적으로 호출하여 실행 환경을 유지합니다.

┌─────────────────────────────────────────────────────────┐
│               EventBridge 워밍업 전략                     │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   EventBridge Rule: rate(5 minutes)                     │
│           │                                             │
│           ▼                                             │
│   Lambda 함수 호출 (워밍업 이벤트)                        │
│           │                                             │
│           ▼                                             │
│   실행 환경 유지 (최대 15분까지 재사용)                   │
│                                                         │
│   장점: 저렴함 (호출 비용만)                              │
│   단점: 동시성 1개만 유지, 완벽하지 않음                  │
└─────────────────────────────────────────────────────────┘

4. 성능 최적화 모범 사례

핸들러 외부 초기화

# ❌ 잘못된 예: 매 호출마다 초기화
def handler(event, context):
    client = boto3.client('dynamodb')  # 매번 생성
    return client.get_item(...)

# ✅ 올바른 예: 핸들러 외부에서 초기화
client = boto3.client('dynamodb')  # 한 번만 생성, 재사용

def handler(event, context):
    return client.get_item(...)  # 기존 연결 재사용

/tmp 디렉토리 캐싱

import os

CACHE_FILE = '/tmp/cached_data.json'

def handler(event, context):
    # 캐시 확인
    if os.path.exists(CACHE_FILE):
        with open(CACHE_FILE) as f:
            data = json.load(f)
    else:
        # 데이터 로드 후 캐싱
        data = load_expensive_data()
        with open(CACHE_FILE, 'w') as f:
            json.dump(data, f)

    return process(data)

최적화 체크리스트

┌─────────────────────────────────────────────────────────┐
│              Lambda 최적화 체크리스트                      │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ✅ SDK 클라이언트는 핸들러 외부에서 초기화               │
│  ✅ DB 연결은 핸들러 외부에서 생성 (연결 재사용)          │
│  ✅ 정적 자산은 /tmp에 캐싱 (512MB 제한)                 │
│  ✅ 불필요한 패키지 제거 (배포 패키지 최소화)             │
│  ✅ AWS Lambda Power Tuning으로 메모리 최적화           │
│  ✅ VPC 연결 최소화 (필요한 경우만)                      │
│  ✅ 프로비전드 동시성은 꼭 필요한 경우만                  │
└─────────────────────────────────────────────────────────┘

5. VPC 연결 고려사항

VPC 내 Lambda 지연 문제

Lambda를 VPC에 연결하면 ENI 생성으로 인해 추가 지연이 발생할 수 있습니다.

과거 (2019년 이전):
VPC Lambda 콜드스타트: 10-30초 추가

현재 (Hyperplane 적용 후):
VPC Lambda 콜드스타트: 일반 Lambda와 유사

VPC 연결이 필요한 경우

필요한 경우불필요한 경우
RDS/Aurora 접근DynamoDB 접근
ElastiCache 접근S3 접근
프라이빗 서브넷 리소스SQS, SNS 접근
EC2 인스턴스 통신API Gateway 호출

6. 비용 최적화

Lambda 비용 구조

총 비용 = 요청 비용 + 컴퓨팅 비용

요청 비용: $0.20 / 100만 요청
컴퓨팅 비용: $0.0000166667 / GB-초

예: 512MB, 1초 실행, 100만 호출/월
= $0.20 + (0.5GB × 1초 × 1,000,000 × $0.0000166667)
= $0.20 + $8.33 = $8.53/월

비용 절감 전략

전략설명
메모리 최적화Power Tuning으로 최적 메모리 찾기
실행 시간 단축핸들러 외부 초기화, 캐싱
Graviton2ARM 기반 프로세서로 20% 비용 절감
Provisioned 최적화Auto Scaling으로 필요한 만큼만

Graviton2 (ARM) 사용

x86_64 대비 Graviton2:
- 가격: 20% 저렴
- 성능: 최대 34% 향상
- 전환: 아키텍처 변경 필요 (arm64)

지원 런타임:
- Python, Node.js, Ruby, Java, .NET, Go

시험 출제 포인트

자주 나오는 문제 유형

  1. 콜드스타트 관련

    • "Java Lambda의 콜드스타트를 줄이려면?" → SnapStart
    • "콜드스타트를 완전히 제거하려면?" → Provisioned Concurrency
  2. 성능 최적화

    • "Lambda 실행 시간이 너무 길다면?" → 메모리 증가 (CPU도 증가)
    • "Lambda 초기화 시간을 줄이려면?" → 핸들러 외부 초기화
  3. 비용 최적화

    • "Lambda 비용을 줄이려면?" → Graviton2, 메모리 최적화
    • "Provisioned Concurrency의 비용 특성?" → 지속 비용 발생

시험 팁

핵심 암기:

  • 메모리 증가 = CPU 증가
  • 콜드스타트 제거 = Provisioned Concurrency
  • Java 콜드스타트 최적화 = SnapStart
  • 비용 절감 = Graviton2 (ARM)

FAQ

Q1: 메모리를 늘리면 항상 비용이 증가하나요?

아니요. 메모리를 늘리면 CPU도 증가하여 실행 시간이 줄어듭니다. 실행 시간이 비례해서 줄어들면 총 비용은 같거나 오히려 줄어들 수 있습니다. Lambda Power Tuning으로 최적 메모리를 찾으세요.

Q2: Provisioned Concurrency와 Reserved Concurrency의 차이는?

  • Provisioned Concurrency: 미리 초기화된 환경 유지 (콜드스타트 제거, 비용 발생)
  • Reserved Concurrency: 최대 동시 실행 수 제한 (비용 없음, 콜드스타트 있음)

Q3: SnapStart는 모든 런타임에서 사용 가능한가요?

아니요. Java 11/17 이상에서만 사용 가능합니다. Python, Node.js 등 다른 런타임에서는 Provisioned Concurrency를 사용하세요.

Q4: /tmp 디렉토리의 용량 제한은?

기본 512MB이며, 최대 10GB까지 늘릴 수 있습니다 (추가 비용 발생). 실행 환경이 재사용되는 동안 /tmp 데이터도 유지됩니다.

Q5: VPC 연결이 성능에 영향을 주나요?

현재는 Hyperplane 기술 덕분에 VPC 연결로 인한 추가 지연이 거의 없습니다. 과거에는 ENI 생성으로 10-30초가 걸렸지만, 지금은 일반 Lambda와 유사합니다.


마무리

Lambda 최적화의 핵심 포인트:

  1. 메모리 = CPU: 메모리를 늘리면 CPU도 증가
  2. 핸들러 외부 초기화: SDK, DB 연결을 재사용
  3. 콜드스타트 해결: Provisioned Concurrency 또는 SnapStart
  4. 비용 최적화: Graviton2, Power Tuning

시험에서는 "Lambda 성능 향상" → 메모리 증가, "콜드스타트 제거" → Provisioned Concurrency를 떠올리세요.