⚡ Serverless Full Stack

13 min read
aws-lambda dynamodb api-gateway cloudfront s3 cognito sqs eventbridge cdk typescript react serverless pay-per-use auto-scaling zero-ops

운영 부담 없이 무한 확장 가능한 서버리스 아키텍처 - AWS Lambda, DynamoDB, API Gateway로 구축하는 현대적 풀스택

⚡ Serverless Full Stack

서버 관리 없이 무한 확장 가능한 현대적 풀스택 아키텍처
"Zero ops, infinite scale, pay only for what you use" - 진정한 클라우드 네이티브


🎯 이 스택이 적합한 경우

✅ 추천하는 경우

  • 불규칙한 트래픽 패턴 (이벤트성, 계절성)
  • 빠른 프로토타이핑과 실험
  • 운영 인력이 없는 소규모 팀
  • 글로벌 배포가 필요한 서비스
  • 비용 최적화가 중요한 프로젝트

❌ 다른 스택을 고려해야 할 경우


🧩 핵심 구성요소

Serverless 컴퓨팅

// Lambda 함수 예제 (TypeScript) import { APIGatewayProxyHandler } from 'aws-lambda'; import { DynamoDB } from 'aws-sdk'; import { z } from 'zod'; const dynamodb = new DynamoDB.DocumentClient(); // 입력 검증 스키마 const CreateUserSchema = z.object({ email: z.string().email(), name: z.string().min(2), role: z.enum(['user', 'admin']).default('user') }); export const createUser: APIGatewayProxyHandler = async (event) => { try { // 요청 파싱 및 검증 const body = JSON.parse(event.body || '{}'); const userData = CreateUserSchema.parse(body); // DynamoDB에 저장 const user = { pk: `USER#${userData.email}`, sk: `PROFILE`, ...userData, createdAt: new Date().toISOString(), userId: crypto.randomUUID() }; await dynamodb.put({ TableName: process.env.USERS_TABLE!, Item: user, ConditionExpression: 'attribute_not_exists(pk)' }).promise(); // EventBridge로 이벤트 발행 await eventbridge.putEvents({ Entries: [{ Source: 'user.service', DetailType: 'UserCreated', Detail: JSON.stringify(user) }] }).promise(); return { statusCode: 201, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ user }) }; } catch (error) { return handleError(error); } }; 

Infrastructure as Code (CDK)

// AWS CDK로 인프라 정의 import * as cdk from 'aws-cdk-lib'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as apigateway from 'aws-cdk-lib/aws-apigateway'; import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'; export class ServerlessStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // DynamoDB 테이블 const usersTable = new dynamodb.Table(this, 'UsersTable', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, sortKey: { name: 'sk', type: dynamodb.AttributeType.STRING }, billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, pointInTimeRecovery: true, stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES }); // Lambda 함수 const createUserFn = new lambda.Function(this, 'CreateUserFunction', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'createUser.handler', code: lambda.Code.fromAsset('dist'), environment: { USERS_TABLE: usersTable.tableName }, timeout: cdk.Duration.seconds(30), memorySize: 1024 }); // API Gateway const api = new apigateway.RestApi(this, 'ServerlessAPI', { restApiName: 'Serverless Service', defaultCorsPreflightOptions: { allowOrigins: apigateway.Cors.ALL_ORIGINS, allowMethods: apigateway.Cors.ALL_METHODS } }); // Lambda 통합 const usersResource = api.root.addResource('users'); usersResource.addMethod('POST', new apigateway.LambdaIntegration(createUserFn) ); // 권한 부여 usersTable.grantReadWriteData(createUserFn); } } 

프론트엔드 (S3 + CloudFront)

// React 앱 배포 설정 const websiteBucket = new s3.Bucket(this, 'WebsiteBucket', { websiteIndexDocument: 'index.html', websiteErrorDocument: 'error.html', publicReadAccess: false, blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL }); // CloudFront 배포 const distribution = new cloudfront.CloudFrontWebDistribution(this, 'Distribution', { originConfigs: [{ s3OriginSource: { s3BucketSource: websiteBucket, originAccessIdentity: oai }, behaviors: [{ isDefaultBehavior: true, compress: true, allowedMethods: cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS, cachedMethods: cloudfront.CloudFrontAllowedCachedMethods.GET_HEAD_OPTIONS, viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, minTtl: cdk.Duration.seconds(0), defaultTtl: cdk.Duration.days(1), maxTtl: cdk.Duration.days(365) }] }], priceClass: cloudfront.PriceClass.PRICE_CLASS_100 }); 

이벤트 기반 아키텍처

// EventBridge 규칙과 타겟 new events.Rule(this, 'UserCreatedRule', { eventPattern: { source: ['user.service'], detailType: ['UserCreated'] }, targets: [ new targets.LambdaFunction(sendWelcomeEmailFn), new targets.SqsQueue(analyticsQueue), new targets.LambdaFunction(updateSearchIndexFn) ] }); // Step Functions로 복잡한 워크플로우 const definition = new sfn.Task(this, 'ProcessOrder') .next(new sfn.Parallel(this, 'ParallelProcessing') .branch(checkInventory) .branch(validatePayment) .branch(calculateShipping) ) .next(new sfn.Choice(this, 'AllChecksPass?') .when(sfn.Condition.booleanEquals('$.allValid', true), fulfillOrder) .otherwise(cancelOrder) ); 

💰 비용 분석 (사용량 기반)

| 서비스 | 무료 티어 | 가격 | 월 10K 요청 | 월 1M 요청 | |--------|-----------|------|-------------|-------------| | Lambda | 1M 요청/월400K GB-초 | $0.20/1M 요청$0.0166/GB-초 | $0 | ~$20 | | API Gateway | 1M 요청/월 (12개월) | $3.50/1M 요청 | $0 | ~$3.50 | | DynamoDB | 25GB 저장25 RCU/WCU | On-demand:$0.25/1M 읽기$1.25/1M 쓰기 | ~$1 | ~$50 | | S3 | 5GB (12개월) | $0.023/GB | ~$0.50 | ~$5 | | CloudFront | 1TB 전송/월 (12개월) | $0.085/GB | $0 | ~$10 | | Cognito | 50K MAU 무료 | $0.0055/MAU | $0 | ~$5 | | 총계 | - | - | ~$1.50 | ~$93.50 |

💡 비용 최적화 팁

// 1. Lambda 메모리 최적화 // AWS Lambda Power Tuning으로 최적 메모리 찾기 const optimalMemory = { simpleAPI: 512, // MB - 간단한 CRUD dataProcessing: 1024, // MB - 데이터 처리 aiInference: 3008 // MB - ML 추론 }; // 2. DynamoDB 비용 절감 const costOptimizedTable = new dynamodb.Table(this, 'OptimizedTable', { // On-Demand vs Provisioned 선택 billingMode: dynamodb.BillingMode.PROVISIONED, readCapacity: 5, writeCapacity: 5, // Auto Scaling 설정 autoScaleReadCapacity: { minCapacity: 1, maxCapacity: 100, targetUtilizationPercent: 70 } }); // 3. S3 라이프사이클 정책 websiteBucket.addLifecycleRule({ id: 'MoveOldFilesToGlacier', transitions: [{ storageClass: s3.StorageClass.GLACIER, transitionAfter: cdk.Duration.days(90) }], expiration: cdk.Duration.days(365) }); 

🚀 구현 로드맵

Week 1: 기초 설정

# AWS CDK 프로젝트 초기화 npx cdk init app --language typescript npm install @aws-cdk/aws-lambda @aws-cdk/aws-apigateway # 로컬 개발 환경 npm install -D @serverless/offline npm install -D aws-sam-cli # 프로젝트 구조 serverless-app/ ├── infra/ # CDK 인프라 코드 ├── backend/ # Lambda 함수들 ├── frontend/ # React 앱 └── shared/ # 공통 타입, 유틸 

Week 2: 백엔드 구현

// Lambda 레이어로 공통 의존성 관리 const commonLayer = new lambda.LayerVersion(this, 'CommonLayer', { code: lambda.Code.fromAsset('layers/common'), compatibleRuntimes: [lambda.Runtime.NODEJS_18_X], description: 'Common dependencies' }); // 함수별 최적화 설정 const functions = { // 빠른 응답이 필요한 API getUser: { memorySize: 512, timeout: cdk.Duration.seconds(10), reservedConcurrentExecutions: 100 }, // 무거운 처리 작업 processData: { memorySize: 3008, timeout: cdk.Duration.minutes(15), reservedConcurrentExecutions: 10 } }; 

Week 3: 프론트엔드 및 인증

// Cognito 사용자 풀 const userPool = new cognito.UserPool(this, 'UserPool', { selfSignUpEnabled: true, signInAliases: { email: true }, autoVerify: { email: true }, standardAttributes: { email: { required: true, mutable: false } }, passwordPolicy: { minLength: 8, requireLowercase: true, requireUppercase: true, requireDigits: true, requireSymbols: true } }); // React 앱에서 Amplify 사용 import { Amplify, Auth } from 'aws-amplify'; Amplify.configure({ Auth: { region: 'us-east-1', userPoolId: 'us-east-1_xxxxx', userPoolWebClientId: 'xxxxx' } }); 

Week 4: 모니터링 및 최적화

// X-Ray 추적 import * as AWSXRay from 'aws-xray-sdk-core'; const AWS = AWSXRay.captureAWS(require('aws-sdk')); // CloudWatch 대시보드 new cloudwatch.Dashboard(this, 'ServerlessDashboard', { widgets: [ [ new cloudwatch.GraphWidget({ title: 'Lambda Invocations', left: [lambdaInvocations], right: [lambdaErrors] }), new cloudwatch.GraphWidget({ title: 'API Gateway Latency', left: [apiLatency] }) ], [ new cloudwatch.GraphWidget({ title: 'DynamoDB Consumed Capacity', left: [dynamoReadCapacity], right: [dynamoWriteCapacity] }) ] ] }); 

🏗️ 아키텍처 패턴

이벤트 기반 패턴

// Event-Driven Architecture interface UserEvent { eventType: 'USER_CREATED' | 'USER_UPDATED' | 'USER_DELETED'; userId: string; timestamp: string; data: any; } // 이벤트 발행 const publishEvent = async (event: UserEvent) => { await eventbridge.putEvents({ Entries: [{ Source: 'user.service', DetailType: event.eventType, Detail: JSON.stringify(event), Time: new Date() }] }).promise(); }; // 이벤트 처리 export const handleUserEvent: EventBridgeHandler<string, UserEvent, void> = async (event) => { const { eventType, userId, data } = event.detail; switch (eventType) { case 'USER_CREATED': await Promise.all([ sendWelcomeEmail(userId), createAnalyticsProfile(userId), indexUserForSearch(data) ]); break; // ... 다른 이벤트 처리 } }; 

서버리스 마이크로서비스

services/ ├── user-service/ │ ├── functions/ │ │ ├── createUser/ │ │ ├── getUser/ │ │ └── updateUser/ │ └── infrastructure/ ├── order-service/ │ ├── functions/ │ └── infrastructure/ └── shared/ ├── types/ ├── utils/ └── layers/ 

API 응답 캐싱

// API Gateway 캐싱 설정 const getUserMethod = userResource.addMethod('GET', new apigateway.LambdaIntegration(getUserFn), { requestParameters: { 'method.request.path.userId': true }, methodResponses: [{ statusCode: '200', responseParameters: { 'method.response.header.Cache-Control': true } }] } ); // Lambda에서 캐시 헤더 설정 return { statusCode: 200, headers: { 'Cache-Control': 'max-age=300', // 5분 캐싱 'Content-Type': 'application/json' }, body: JSON.stringify(userData) }; 

🔄 대안 및 변형

멀티 클라우드 옵션

| AWS | Azure | GCP | Cloudflare | |-----|-------|-----|------------| | Lambda | Functions | Cloud Functions | Workers | | DynamoDB | Cosmos DB | Firestore | Workers KV | | API Gateway | API Management | API Gateway | - | | S3 | Blob Storage | Cloud Storage | R2 | | CloudFront | CDN | Cloud CDN | CDN | | Cognito | AD B2C | Identity Platform | Access |

엣지 우선 변형

// Cloudflare Workers 예제 export default { async fetch(request, env, ctx) { const url = new URL(request.url); // KV 스토어에서 데이터 조회 const cached = await env.KV.get(url.pathname); if (cached) { return new Response(cached, { headers: { 'Content-Type': 'application/json' } }); } // 오리진 요청 const response = await fetch(request); const data = await response.json(); // 엣지에 캐싱 ctx.waitUntil( env.KV.put(url.pathname, JSON.stringify(data), { expirationTtl: 300 }) ); return new Response(JSON.stringify(data)); } }; 

🏆 성공 사례

Coca-Cola (Vending Pass)

  • 규모: 100개국, 수백만 사용자
  • 비용: 기존 대비 65% 절감
  • 특징: 완전 서버리스, 자동 확장

iRobot

  • 이전: EC2 기반 모놀리스
  • 현재: 100% 서버리스
  • 성과: 운영 비용 80% 절감

FINRA

  • 규모: 일일 370억 이벤트 처리
  • 아키텍처: Lambda + Kinesis + S3
  • 비용: 기존 온프레미스 대비 50% 절감

📚 필수 리소스

학습 자료

도구 및 프레임워크

커뮤니티


💬 실무자 조언

"서버리스는 코드만 작성하면 된다고 생각하기 쉽지만, 분산 시스템의 모든 복잡성은 그대로입니다. 특히 디버깅이 어려워요." - @serverless_veteran

"콜드 스타트 때문에 고민 많았는데, Provisioned Concurrency로 해결했습니다. 비용은 좀 들지만 일관된 성능이 중요하면 필수예요." - @performance_focused

"DynamoDB 모델링이 핵심이에요. Single Table Design 제대로 못하면 나중에 마이그레이션 지옥입니다." - @nosql_expert

"비용 모니터링 꼭 하세요. 무한 루프 한 번이면 월 청구서가 폭탄됩니다. Budget Alert는 필수!" - @cost_conscious_dev


⚡ 성능 최적화

Lambda 콜드 스타트 최소화

// 1. 번들 크기 최적화 // webpack.config.js module.exports = { externals: ['aws-sdk'], // SDK는 Lambda 런타임에 포함 optimization: { minimize: true, usedExports: true } }; // 2. 초기화 코드 최적화 let dynamoClient: DynamoDB.DocumentClient; const getClient = () => { if (!dynamoClient) { dynamoClient = new DynamoDB.DocumentClient({ httpOptions: { connectTimeout: 5000, timeout: 5000 } }); } return dynamoClient; }; // 3. Provisioned Concurrency const criticalFunction = new lambda.Function(this, 'CriticalFunction', { // ... 다른 설정 provisionedConcurrentExecutions: 5 }); 

DynamoDB 최적화

// 배치 작업으로 비용 절감 const batchWrite = async (items: any[]) => { const chunks = chunk(items, 25); // DynamoDB 배치 제한 for (const chunk of chunks) { await dynamodb.batchWrite({ RequestItems: { [tableName]: chunk.map(item => ({ PutRequest: { Item: item } })) } }).promise(); } }; 

🚨 주의사항

제한사항

  • Lambda 실행 시간: 최대 15분
  • API Gateway 타임아웃: 29초
  • Lambda 페이로드: 6MB (동기), 256KB (비동기)
  • DynamoDB 아이템 크기: 400KB

모범 사례

  1. 멱등성: 모든 함수는 멱등적으로 설계
  2. 에러 처리: DLQ (Dead Letter Queue) 필수
  3. 보안: 최소 권한 원칙 적용
  4. 모니터링: CloudWatch Logs Insights 활용

마지막 업데이트: 2025-01-28
기여하기: GitHub에서 편집

Found this helpful? Share it with others!
Tweet

🔗 Related Content

You might also be interested in these articles

🏢 company

🏢 Canva 기술 스택 분석

캔바가 1억 명 이상의 사용자에게 쉽고 강력한 디자인 도구를 제공하는 기술 스택 심층 분석 - Java, TypeScript, AWS로 구축한 대규모 디자인 플랫폼

35 min read
canva, java+10
Read more
🏗️ stack

🚀 Modern SaaS MVP Stack

4주 안에 SaaS를 출시하기 위한 검증된 기술 스택 - Next.js, Supabase, Stripe로 빠르게 시작하기

6 min read
nextjs, supabase+13
Read more
🏗️ stack

🔄 Realtime Collaboration Stack

Figma, Notion 같은 실시간 협업 앱 구축을 위한 기술 스택 - WebSocket, CRDT, WebRTC로 만드는 동시 편집 시스템

20 min read
nodejs, socketio+13
Read more
🏢 company

🏢 Figma 기술 스택 분석

피그마가 브라우저에서 실시간 협업 디자인 툴을 구현한 기술 스택 심층 분석 - C++, WebAssembly, WebGL로 만든 차세대 디자인 플랫폼

24 min read
figma, c+++11
Read more
🏢 company

🏢 Notion 기술 스택 분석

노션이 수천만 사용자에게 All-in-One 워크스페이스를 제공하는 기술 스택 심층 분석 - 블록 기반 에디터, 실시간 협업, 그리고 확장 가능한 데이터베이스

26 min read
notion, typescript+11
Read more
🏢 company

🏢 Vercel 기술 스택 분석

버셀이 프론트엔드 배포의 미래를 만드는 기술 스택 심층 분석 - Next.js, Edge Functions, 그리고 글로벌 엣지 네트워크

31 min read
vercel, nextjs+9
Read more

Found this helpful?

Help us improve this content by contributing on GitHub or sharing your feedback with the community.