AWS Lambda Cold Start 최적화 여정
Part 3: 실행 및 검증 - 데이터 기반 최적화의 실제 적용
1부에서는 "첫 로딩 지연" 문제의 원인이 프론트엔드 Lambda의 긴 콜드 스타트 시간임을 데이터로 증명하고, 이를 해결하기 위한 최종 전략으로 "Lambda 메모리 상향"과 "저비용 워밍"을 채택했다.
2부에서는 이 전략을 실제로 어떻게 인프라 코드에 적용했는지, 그리고 그 결과 성능이 얼마나 개선되었는지를 다시 데이터를 통해 검증하는 과정을 상세히 다룰 예정이다.
6. 해결책 1: Lambda 메모리 상향 적용
데이터 분석을 통해 확인된 가장 확실한 개선책은 FrontendServerLambda의 메모리를 1024MB에서 2048MB로 상향하는 것이었다. 이는 AWS CDK로 관리되는 인프라 코드에서 단 한 줄을 수정하는 것으로 간단하게 적용할 수 있다.
코드: apps/infra/lib/blog-stack.ts
// ... const serverLambda = new lambda.DockerImageFunction(this, 'FrontendServerLambda', { functionName: `blog-frontend-server-${this.stackName}`, description: 'Renders the Next.js frontend application (SSR).', code: lambda.DockerImageCode.fromEcr(ecrRepository, { tagOrDigest: imageTag.valueAsString }), // [수정] 메모리 크기를 1024에서 2048로 상향 조정 memorySize: 2048, timeout: Duration.seconds(60), // 메모리 증가에 맞춰 타임아웃도 넉넉하게 조정 architecture: lambda.Architecture.ARM_64, // ... }); // ...
이 코드 변경은 Lambda에 할당되는 vCPU 성능을 향상시켜, 콜드 스타트의 여러 단계 중 CPU 집약적인 "애플리케이션 초기화" 시간을 직접적으로 단축시키는 효과를 가져온다.
7. 해결책 2: 저비용 워밍(Keep-Warm) 전략 구현
다음으로, 콜드 스타트의 발생 빈도 자체를 줄이기 위해 EventBridge Scheduler를 사용하여 10분 간격으로 FrontendServerLambda를 호출하는 워밍 규칙을 추가했다.
코드: apps/infra/lib/blog-stack.ts
// 파일 상단에 scheduler 모듈 import 추가 import * as scheduler from 'aws-cdk-lib/aws-scheduler'; // ... (serverLambda 정의 후) // 1. EventBridge Scheduler가 Lambda를 호출할 수 있는 IAM Role 생성 const warmerRole = new iam.Role(this, 'FrontendWarmerRole', { assumedBy: new iam.ServicePrincipal('scheduler.amazonaws.com'), }); serverLambda.grantInvoke(warmerRole); // 2. 10분 간격으로 FrontendServerLambda를 호출하는 EventBridge 스케줄 생성 new scheduler.CfnSchedule(this, 'FrontendWarmerSchedule', { name: `blog-frontend-warmer-${this.stackName}`, description: 'Warms up the FrontendServerLambda every 10 minutes.', scheduleExpression: 'rate(10 minutes)', flexibleTimeWindow: { mode: 'OFF', }, target: { arn: serverLambda.functionArn, roleArn: warmerRole.roleArn, // 워밍 호출임을 식별하기 위한 페이로드 input: JSON.stringify({ source: 'eventbridge-scheduler-warmer' }), }, });
이 CDK 코드는 EventBridge가 FrontendServerLambda를 주기적으로 호출하는 데 필요한 모든 권한과 규칙을 정의한다. 이 "가짜" 호출을 통해 Lambda 실행 환경의 유휴 시간이 초기화되어, 컨테이너가 회수되지 않고 계속 "웜" 상태를 유지하게 된다.
8. 최종 검증: "Before & After" 데이터로 증명하는 개선 효과
위 두 가지 해결책을 모두 적용하고 재배포한 후, 다시 의도적으로 콜드 스타트를 유발하여 성능 개선 효과를 측정했다.
결과: 콜드 스타트 시간의 극적인 단축

| 메모리 크기 (MB) | 평균 콜드 스타트 시간 (ms) | p95 콜드 스타트 시간 (ms) |
|---|---|---|
| 1024 (Before) | 3885.82 (약 3.8초) | 4792.28 (약 4.8초) |
| 2048 (After) | 2441.71 (약 2.4초) | 3291.74 (약 3.3초) |
데이터는 명확한 결과를 보여주었다. 메모리 상향만으로 평균 콜드 스타트 시간은 약 37% 개선되었다.
워밍 효과 검증

워밍 전략이 적용된 후, CloudWatch 로그를 확인하면 10분 간격으로 워밍 호출이 꾸준히 들어오는 것을 볼 수 있다. 이 시간 간격 내에 블로그에 접속했을 때의 REPORT 로그에는 Init Duration 항목이 아예 존재하지 않는다. 이는 콜드 스타트 없이 "웜 스타트"로 요청이 처리되었음을 의미하며, 이때의 Duration은 100ms 미만으로 매우 빠른 응답 속도를 보여준다.

이 검증을 통해, "메모리 상향"으로 콜드 스타트 자체의 충격을 줄이고, "저비용 워밍"으로 그 발생 확률을 최소화하는 우리의 전략이 성공적으로 동작함을 확인했다.
9. 현재 해결책의 유효 범위 분석: "최적의 균형점"
현재 채택한 "2048MB 메모리 + 10분 간격 워밍" 조합은 현 상황의 제약 조건 아래에서 내릴 수 있는 가장 합리적인 결정이다.
먼저, 이 전략은 두 가지 측면에서 효과적이다. 첫째, 메모리 상향을 통해 콜드 스타트 자체의 지연 시간을 3.8초에서 2.4초로 단축하여 최악의 사용자 경험을 개선했다. 둘째, 10분 간격의 워밍을 통해 대부분의 사용자는 콜드 스타트를 아예 겪지 않고 100ms 미만의 웜 스타트로 빠른 응답을 경험하게 된다.
물론, 이 해결책에도 명확한 한계는 존재한다. 워밍 호출의 간격인 10분 사이에 처음으로 접속하는 사용자나, 순간적인 트래픽 증가로 준비된 웜 인스턴스 이상의 동시 요청이 발생할 경우 여전히 2.4초의 지연은 피할 수 없다.
그러나 현재 블로그의 트래픽 규모와 패턴을 고려할 때, 이러한 한계 상황이 발생할 확률은 매우 낮다고 판단했다. 따라서 현재의 해결책은 '프리티어 준수' 와 'SSR 아키텍처 유지' 라는 핵심 제약 조건 하에서, 성능, 비용, 개발 복잡도 사이의 최적의 균형점을 찾은 이상적인 사례라고 판단할 수 있다.
10. 미래를 위한 로드맵: 트래픽 성장에 따른 아키텍처 진화
현재의 해결책은 최종적인 아키텍처가 아니며, 블로그의 성장에 따라 진화해야 하는 로드맵의 첫 단계에 해당한다. 트래픽 임계점에 따른 구체적인 아키텍처 진화 계획과 비용 예측은 다음과 같다.
-
Level 1 (현재): 2048MB Lambda + 워밍
- 상황: 월간 활성 사용자(MAU) 1천 명 미만, 동시 접속자 20명 미만의 개인 블로그.
- 비용 분석:
- 워밍 비용: 10분마다 호출되는 워밍용 Lambda는 한 달에 약 4,320회 실행된다. 각 호출이 웜 스타트(약 100ms)로 처리된다고 가정하면, 총 컴퓨팅 시간은
4,320회 × 0.1초 × (2048MB / 1024MB/GB)= 약 864 GB-초이다. - 실제 트래픽 비용: 현재 트래픽은 미미한 수준이다.
- 결론: 워밍과 실제 트래픽을 합산해도 AWS Lambda 프리티어(월 100만 건 요청, 40만 GB-초) 범위 내에 충분히 포함된다. EventBridge Scheduler 역시 프리티어 내에서 해결되므로, 현재 아키텍처의 월 운영 비용은 실질적으로 $0에 수렴한다.
- 워밍 비용: 10분마다 호출되는 워밍용 Lambda는 한 달에 약 4,320회 실행된다. 각 호출이 웜 스타트(약 100ms)로 처리된다고 가정하면, 총 컴퓨팅 시간은
-
Level 2 (월간 활성 사용자 1만 명 이상 / 동시 접속자 50명 이상):
- 해결책: 프로비저닝된 동시성 (Provisioned Concurrency) 1~2개 할당.
- 트리거: 이 단계에서는 사용자가 콜드 스타트를 경험할 확률이 비즈니스적으로 무시할 수 없는 수준이 된다. 예를 들어, 동시에 50명의 사용자가 접속했을 때 웜 상태의 인스턴스가 부족하여 일부 사용자가 2.4초의 지연을 겪는 상황이 발생할 수 있다. 이는 사용자 이탈의 직접적인 원인이 된다.
- 비용 분석:
- 프로비저닝 비용: 서울 리전(ap-northeast-2)의 ARM 아키텍처 기준, 2048MB(2GB) Lambda 인스턴스 1개를 한 달 내내 프로비저닝하는 비용은 다음과 같이 예측된다.
2GB × $0.0000048611/GB-초 × 3,600초/시간 × 24시간/일 × 30일/월≈ 월 $25.2
- 결과: 월 약 25달러의 고정 비용으로 콜드 스타트를 사실상 완벽하게 제거할 수 있다. 이는 불특정 다수의 사용자가 겪을 수 있는 부정적인 경험을 방지하는 '보험' 비용으로, 서비스의 신뢰도를 확보하기 위한 합리적인 투자이다.
- 프로비저닝 비용: 서울 리전(ap-northeast-2)의 ARM 아키텍처 기준, 2048MB(2GB) Lambda 인스턴스 1개를 한 달 내내 프로비저닝하는 비용은 다음과 같이 예측된다.
-
Level 3 (월간 활성 사용자 10만 명 이상 / 동시 접속자 수백 명 이상):
- 해결책: SSG/ISR로의 아키텍처 전환.
- 트리거: 트래픽이 폭발적으로 증가하면 SSR Lambda의 비용이 부담되기 시작한다. 예를 들어, MAU 10만, 사용자당 월 20회 요청이 발생한다고 가정하면 월 200만 건의 요청이 발생한다.
- SSR Lambda 예상 비용: 프리티어를 초과하는 100만 건의 요청($0.2)과, 평균 응답시간 200ms 기준 약 40만 GB-초의 컴퓨팅 비용(약 $5.3)을 합산하면 월 $5.5 정도가 된다. 여기서 트래픽이 10배로 늘어난다면 비용 역시 월 $50~$60 이상으로 선형적으로 증가한다.
- 비용 분석 (SSG/ISR 전환 시):
- 주요 비용: 컴퓨팅(Lambda) 비용에서 콘텐츠 전송(CloudFront) 비용으로 전환된다.
- 예상 비용: 월 2,000만 요청과 페이지당 150KB 전송을 가정하면, CloudFront에서 약 3TB의 데이터 전송이 발생한다. 이 경우 요청 비용(약 $18)과 데이터 전송 비용이 발생하지만, Lambda처럼 모든 요청에 대해 CPU 집약적인 렌더링을 수행하지 않으므로 전체적인 비용 효율성과 응답 성능은 비교할 수 없을 정도로 향상된다. 아키텍처 전환으로 최고의 성능과 비용 효율성을 동시에 달성하는 단계이다.
-
Level 4 (그 이상):
- 해결책: ECS/EKS 또는 EC2 기반의 상시 대기 서버.
- 트리거: 실시간 상호작용, WebSocket, 긴 처리 시간(>15분) 등 Lambda의 근본적인 제약이 비즈니스 로직 구현에 한계로 작용하는 시점이다.
- 비용 분석:
- 최소 비용: 가장 작은 Fargate 인스턴스(0.25 vCPU, 0.5GB RAM) 2대를 로드 밸런서와 함께 운영해도, 유휴 상태에서도 최소 월 $40~$50의 기본 비용이 발생한다.
- 결과: 이 단계는 비용 절감이 아닌, 아키텍처의 유연성과 제어권 확보가 목적이다. Pay-per-use 모델에서 벗어나 서버 리소스를 직접 관리하며, Lambda 환경에서는 불가능했던 복잡한 요구사항을 해결하게 된다.
네, 알겠습니다. 논의된 내용을 정확히 반영하여, 11번을 '가능성' 파트로, 12번을 '결론' 파트로 나누고, 각 파트의 핵심 메시지를 강조하여 다시 작성하겠습니다.
11. 남겨진 과제와 아키텍처의 가능성
이번 최적화 과정에서 현재 아키텍처를 유지하며 성능을 개선하는 데 집중했지만, 장기적인 관점에서 고려할 수 있는 아키텍처의 가능성은 여전히 존재한다.
-
스트리밍 SSR (Streaming SSR): Next.js App Router의
Suspense등을 활용한 스트리밍 SSR은 TTFB(Time To First Byte) 개선 없이도 사용자의 체감 성능을 높일 수 있는 매력적인 기술이다. 하지만 이를 효과적으로 적용하기 위해서는 기존 컴포넌트 구조의 상당한 리팩토링이 선행되어야 했다. 현재 블로그의 복잡도와 시급성을 고려했을 때, 이는 'Quick-Win' 전략에 부합하지 않는다고 판단했다. -
SSG/ISR로의 전환: 대규모 트래픽 환경에서 최고의 성능과 비용 효율을 보여주는 아키텍처는 단연 SSG/ISR이다. 이 가능성을 충분히 인지하고 있으나, 이는 아키텍처의 근본적인 변경을 의미한다. 현재 트래픽 수준에서는 SSR의 비용적, 성능적 한계가 전혀 드러나지 않으므로, 현시점에서의 전환은 불필요한 오버 엔지니어링이라고 결론 내렸다.
따라서, 위에 언급된 기술들을 도입하지 않은 것은 그것들을 몰라서가 아니다. 오히려 현재 프로젝트의 단계와 제약 조건, 투입 대비 효용을 종합적으로 분석한 결과, 지금의 SSR 아키텍처를 유지하며 최적화하는 것이 가장 합리적이고 이상적인 선택이라는 전략적 판단을 내린 것이다.
12. 결론: 당연하게 여겼던 트레이드오프를 넘어서
처음 'Lambda + ECR' 조합으로 컨테이너 기반의 프론트엔드 서버를 구축하기로 했을 때, 콜드 스타트는 당연히 감수해야 할 트레이드오프라고 생각했다. AWS 프리티어라는 막강한 이점을 누리기 위해 치러야 하는 어쩔 수 없는 비용이라고 여겼다.
하지만 이번 최적화 여정은 그 당연하게 여겼던 가정을 정면으로 돌파하는 과정이었다.
이번 최적화를 진행하며 가장 큰 성과는 프론트엔드 서버를Lambda를 사용하여 프리티어의 혜택을 온전히 누리는 동시에, 그 한계점으로 당연시 여겼던 초기 진입시 콜드 스타트 문제마저 추가 비용 없이 해결했다는 사실이었다. 우리는 컨테이너 기반 개발의 일관성과 편리함, 서버리스의 비용 효율성이라는 두 마리 토끼를 모두 잡았고, 그 과정에서 발생할 수 있는 가장 큰 사용자 경험 저하 요인을 성공적으로 제어해냈다.
결국 이 모든 최적화 과정은 주어진 제약과 예산 안에서 문제를 단순히 트레이드 오프로 생각하고 수용하는 것이 아니라, 데이터를 통해 측정하고 분석하여 최적의 해답을 찾아 나가는 경험을 했다고 생각한다. 그리고 그 끝에서, 당연하게 여겼던 한계를 넘어선 결과물을 만들어냈다는 점에서 깊은 성취감을 느끼고 있다.😎
