AWS Lambda 완벽 가이드 | Serverless·API Gateway·DynamoDB·S3·EventBridge

AWS Lambda 완벽 가이드 | Serverless·API Gateway·DynamoDB·S3·EventBridge

이 글의 핵심

AWS Lambda로 서버리스 앱을 구축하는 완벽 가이드입니다. 함수 작성, API Gateway, DynamoDB, S3, EventBridge, Cold Start 최적화까지 실전 예제로 정리했습니다.

실무 경험 공유: 전통적인 서버를 Lambda로 마이그레이션하면서, 인프라 비용을 80% 절감하고 확장성을 무한대로 확보한 경험을 공유합니다.

들어가며: “서버 관리가 부담돼요”

실무 문제 시나리오

시나리오 1: 트래픽이 급증하면 서버가 다운돼요
EC2 인스턴스가 부족합니다. Lambda는 자동으로 확장합니다.

시나리오 2: 서버 비용이 너무 많이 나와요
24시간 실행되는 서버 비용이 큽니다. Lambda는 사용한 만큼만 과금됩니다.

시나리오 3: 서버 관리가 복잡해요
패치, 보안, 모니터링이 번거롭습니다. Lambda는 AWS가 관리합니다.


1. AWS Lambda란?

핵심 특징

AWS Lambda는 서버리스 컴퓨팅 서비스입니다.

주요 장점:

  • 서버 관리 불필요: AWS가 관리
  • 자동 확장: 무한 확장
  • 사용량 기반 과금: 실행 시간만 과금
  • 이벤트 기반: S3, DynamoDB 등과 통합
  • 빠른 배포: 코드만 업로드

비용:

  • 월 100만 요청: 무료
  • 이후: $0.20 / 100만 요청

2. 첫 번째 Lambda 함수

Node.js

// index.js
export const handler = async (event) => {
  console.log('Event:', JSON.stringify(event));

  return {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Hello from Lambda!',
      input: event,
    }),
  };
};

Python

# lambda_function.py
import json

def lambda_handler(event, context):
    print(f'Event: {json.dumps(event)}')
    
    return {
        'statusCode': 200,
        'body': json.dumps({
            'message': 'Hello from Lambda!',
            'input': event
        })
    }

3. API Gateway 통합

REST API

# serverless.yml (Serverless Framework)
service: my-api

provider:
  name: aws
  runtime: nodejs20.x
  region: us-east-1

functions:
  getUsers:
    handler: handlers/users.getUsers
    events:
      - http:
          path: users
          method: get
          cors: true

  getUser:
    handler: handlers/users.getUser
    events:
      - http:
          path: users/{id}
          method: get
          cors: true

  createUser:
    handler: handlers/users.createUser
    events:
      - http:
          path: users
          method: post
          cors: true

Handler

// handlers/users.js
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, ScanCommand, GetCommand, PutCommand } from '@aws-sdk/lib-dynamodb';

const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

export const getUsers = async (event) => {
  const command = new ScanCommand({
    TableName: 'Users',
  });

  const result = await docClient.send(command);

  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*',
    },
    body: JSON.stringify(result.Items),
  };
};

export const getUser = async (event) => {
  const { id } = event.pathParameters;

  const command = new GetCommand({
    TableName: 'Users',
    Key: { id },
  });

  const result = await docClient.send(command);

  if (!result.Item) {
    return {
      statusCode: 404,
      body: JSON.stringify({ error: 'User not found' }),
    };
  }

  return {
    statusCode: 200,
    body: JSON.stringify(result.Item),
  };
};

export const createUser = async (event) => {
  const body = JSON.parse(event.body);

  const command = new PutCommand({
    TableName: 'Users',
    Item: {
      id: Date.now().toString(),
      ...body,
      createdAt: new Date().toISOString(),
    },
  });

  await docClient.send(command);

  return {
    statusCode: 201,
    body: JSON.stringify({ message: 'User created' }),
  };
};

4. DynamoDB 통합

테이블 생성

# serverless.yml
resources:
  Resources:
    UsersTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: Users
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        KeySchema:
          - AttributeName: id
            KeyType: HASH
        BillingMode: PAY_PER_REQUEST

5. S3 이벤트

S3 트리거

functions:
  processImage:
    handler: handlers/images.process
    events:
      - s3:
          bucket: my-images-bucket
          event: s3:ObjectCreated:*
          rules:
            - suffix: .jpg

Handler

// handlers/images.js
import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
import sharp from 'sharp';

const s3 = new S3Client({});

export const process = async (event) => {
  for (const record of event.Records) {
    const bucket = record.s3.bucket.name;
    const key = record.s3.object.key;

    // 원본 이미지 가져오기
    const getCommand = new GetObjectCommand({ Bucket: bucket, Key: key });
    const { Body } = await s3.send(getCommand);

    // 리사이징
    const resized = await sharp(Body)
      .resize(800, 600)
      .toBuffer();

    // 저장
    const putCommand = new PutObjectCommand({
      Bucket: bucket,
      Key: `resized/${key}`,
      Body: resized,
    });

    await s3.send(putCommand);
  }

  return { statusCode: 200, body: 'Processed' };
};

6. EventBridge (스케줄링)

functions:
  dailyReport:
    handler: handlers/reports.daily
    events:
      - schedule:
          rate: cron(0 9 * * ? *)  # 매일 오전 9시
          enabled: true

7. Cold Start 최적화

1. 런타임 선택

provider:
  runtime: nodejs20.x  # 빠른 Cold Start
  # runtime: python3.12  # 느린 Cold Start

2. 메모리 증가

functions:
  api:
    handler: index.handler
    memorySize: 1024  # 기본 128MB → 1024MB

3. Provisioned Concurrency

functions:
  api:
    handler: index.handler
    provisionedConcurrency: 2  # 항상 2개 준비

4. 번들 최적화

// webpack.config.js
module.exports = {
  target: 'node',
  mode: 'production',
  externals: ['aws-sdk'],  // AWS SDK 제외
  optimization: {
    minimize: true,
  },
};

8. 실전 예제: 이미지 업로드 API

// handlers/upload.js
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

const s3 = new S3Client({});

export const getUploadUrl = async (event) => {
  const { filename, contentType } = JSON.parse(event.body);

  const command = new PutObjectCommand({
    Bucket: 'my-uploads-bucket',
    Key: `uploads/${Date.now()}-${filename}`,
    ContentType: contentType,
  });

  const uploadUrl = await getSignedUrl(s3, command, { expiresIn: 3600 });

  return {
    statusCode: 200,
    body: JSON.stringify({ uploadUrl }),
  };
};

정리 및 체크리스트

핵심 요약

  • AWS Lambda: 서버리스 컴퓨팅
  • 자동 확장: 무한 확장
  • 사용량 기반 과금: 실행 시간만
  • API Gateway: REST API 구축
  • DynamoDB: NoSQL 데이터베이스
  • S3: 파일 저장소

구현 체크리스트

  • Lambda 함수 작성
  • API Gateway 설정
  • DynamoDB 연동
  • S3 이벤트 처리
  • Cold Start 최적화
  • 모니터링 설정
  • 배포

같이 보면 좋은 글

  • Cloudflare Workers AI 가이드
  • Terraform 실전 가이드
  • FastAPI 완벽 가이드

이 글에서 다루는 키워드

AWS, Lambda, Serverless, API Gateway, DynamoDB, S3, Cloud

자주 묻는 질문 (FAQ)

Q. Lambda vs EC2, 어떤 게 나은가요?

A. Lambda는 간헐적 트래픽에 유리합니다. EC2는 지속적 트래픽에 유리합니다. 비용과 관리 편의성을 고려하세요.

Q. Cold Start가 얼마나 걸리나요?

A. Node.js는 100-300ms, Python은 200-500ms, Java는 1-3초입니다. Provisioned Concurrency로 제거할 수 있습니다.

Q. 실행 시간 제한이 있나요?

A. 최대 15분입니다. 더 긴 작업은 Step Functions나 ECS를 사용하세요.

Q. 프로덕션에서 사용해도 되나요?

A. 네, Netflix, Coca-Cola 등 많은 기업에서 사용합니다.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3