AWS Lambda 인프라 구축 및 Spring Boot 연동 가이드

JH.KIM·2025년 7월 15일

📌 들어가며

대용량 이미지 처리 파이프라인을 전통적인 EC2 + Cron + 파일 서버 방식으로 운영하다 보면

  • 빈번한 스케일 업/다운 및 인스턴스 관리
  • 파일 I/O 병목으로 인한 지연
  • 사용량이 적은 시간에도 계속 발생하는 서버 비용

과 같은 문제를 겪게 됩니다.

AWS LambdaS3 를 결합한 서버리스(Serverless) 접근은 이런 문제를 근본적으로 해소합니다.

선택이유
Lambda이벤트 기반 실행과 초 단위 과금 ► 비용 최적화 / 인프라 관리 부담 최소화
S3내구성 11 9(99.999999999%)·무제한 확장 / 정적 URL 배포(CloudFront) 연계 용이

본 글에서는 Spring Boot API 서버 ↔ Lambda(Image Processor) ↔ S3 로 이루어진 파이프라인을 예제로, 

  • 인프라 설계 (Serverless Framework)
  • Lambda Invoke 방식 vs API Gateway 호출 비교
  • 캐싱 전략 (MongoDB / Redis / S3 패턴)
  • 운영·보안 Best Practice

를 단계별로 정리합니다.


1️⃣ 전체 아키텍처 개요

1‑1. 구성 요소

컴포넌트역할
API 서버 (Spring Boot + ECS Fargate)이미지 URL 스크랩핑 → RDB 저장 → Lambda Invoke
Image Processor Lambda 중복 검사 → 이미지 다운로드 → S3 업로드 → 콜백
S3 버킷최종 이미지 저장 / CloudFront Origin
캐시 DB url ⇆ s3Uri 매핑 유지(30 일)
RDB 비즈니스 메타데이터 보관

1‑2. 시스템 흐름도

[API 서버]
    │
    │ Invoke (async)
    ▼
[Lambda]
  ├───▶ HEAD / Cache ───▶ [MongoDB·Redis]
  ├───▶ Download ───────▶ [원본 URL]
  ├───▶ PutObject ──────▶ [S3]
  └───▶ Callback ───────▶ [API 서버]

호환성 Tip: 원본이 이미 S3 안에 있다면 CopyObject 로 대체해 네트워크 I/O 비용을 줄일 수 있습니다.


2️⃣ Serverless Framework 기반 Lambda 인프라 구성

2‑1. serverless.yml 요약

service: image-processor
frameworkVersion: '3'
useDotenv: true  # .env 로컬 변수 자동 로드

provider:
  name: aws
  region: ap-northeast-2
  runtime: nodejs18.x
  timeout: 900  # 15 분 – 대용량 이미지 처리 대비
  iamRoleStatements:  # 최소 권한만 부여
    # S3 업로드
    - Effect: Allow
      Action: [ s3:PutObject, s3:HeadObject ]
      Resource: arn:aws:s3:::prod-bucket/*
    # (선택) SQS 전송
    - Effect: Allow
      Action: sqs:SendMessage
      Resource: arn:aws:sqs:ap-northeast-2:123456789012:fc-review-*

functions:
  processImage:
    handler: dist/handler.processImage
    memorySize: 512

plugins:
  - serverless-dotenv-plugin   # 환경변수
  - serverless-esbuild         # 고속 번들/최적화

custom:
  esbuild:
    bundle: true
    minify: true
    external: []      # 모든 의존성을 번들링해 콜드스타트 최소화
    target: node18

콜드 스타트 최적화
esbuild + minify + external [] + 512 MB 메모리 조합으로 초기 로딩 시간을 ~200 ms 이하로 단축할 수 있습니다.

2‑2. VPC 구성 시 주의

  • Lambda를 VPC Subnet에 넣으면 ENI 할당 → 초기 콜드 스타트가 길어짐

  • Solutions

    1. 인터넷 통신이 필요 없다면 VPC NAT 대신 VPC Endpoint for S3 사용
    2. 혹은 VPC 외부(프라이빗 EndPoint X)에서 실행해 ENI 생성 자체를 피함

3️⃣ Spring Boot에서 Lambda Invoke ✨

3‑1. 왜 Invoke 방식인가?

API GatewayInvokeFunction (SDK)
REST 엔드포인트 공개 → 추가 과금($3.5/mil)무료 (Lambda 호출 비용만)
멀티 파이프라인일 때 라우팅 복잡내부 서비스 간 간단 호출
인증·Throttle 설정 필요IAM Role 정책만 있으면 끝

내부 BFF(Batch) 작업이나 비공개 서버↔Lambda 시나리오는 Invoke가 비용·보안 측면에서 유리합니다.

3‑2. Kotlin(Spring) 코드 예시

@Service
class ImageLambdaInvoker(
  private val lambda: LambdaClient,
  @Value("\${app.lambda.functionName}")
  private val functionName: String
) {
  fun invoke(recordId: Long, originalUrl: String, callbackUrl: String) {
    val payload = mapOf(
      "recordId" to recordId,
      "originalUrl" to originalUrl,
      "callbackUrl" to callbackUrl
    )
    lambda.invoke {
      functionName(functionName)
      invocationType(InvocationType.EVENT) // 비동기 호출
      payload(SdkBytes.fromUtf8String(ObjectMapper().writeValueAsString(payload)))
    }
  }
}

3‑3. 콜백 처리 패턴

  • SQS 이벤트 기반 (대량/재시도 용이)
    Lambda → SendMessage → API 서버가 큐를 폴링 또는 SQS Listener(@SqsListener)
  • HTTP Webhook (즉시 처리)
    Lambda → POST /images/{id}/callback
    Spring Boot @PostMapping 으로 수신

4️⃣ Lambda 핸들러 구현 (TypeScript)

export const handler = async (event) => {
  const { recordId, originalUrl, callbackUrl } = JSON.parse(event.body!);

  // 1) 캐시 조회 (Mongo/Redis/S3)
  const cached = await getCachedS3Uri(originalUrl);
  let s3Uri = cached;

  if (!cached) {
    // 2) 이미지 다운로드
    const { data, contentType } = await fetchImage(originalUrl);

    // 3) S3 업로드 (날짜별 경로)
    const key = `${new Date().toISOString().slice(0,10)}/${Date.now()}.jpg`;
    s3Uri = await uploadToS3(data, contentType, key, process.env.S3_BUCKET!);

    // 4) 캐시 저장
    await setCache(originalUrl, s3Uri);
  }

  // 5) 콜백 (Webhook or SQS)
  await postCallback(recordId, callbackUrl, s3Uri);
};

5️⃣ 캐싱 전략 – 간략 소개

방법TTL 적용장점단점
MongoDB TTL 인덱스expireAfterSeconds문서형 메타데이터, upsert 편리연결 수·콜드스타트 비용
Redis SETEXKey 자체 만료초고속 읽기/쓰기메모리 비용
S3 객체 패턴 HeadObject없음외부 DB 불필요HeadObject 비용·레이턴시

소규모 트래픽 → MongoDB 무료 티어,
초고속 응답 요구 → Redis,
DB 운영 최소화 → S3 객체 패턴이 추천됩니다.


6️⃣ 운영 및 성능 고려사항

6‑1. Lambda 콜드 스타트

  • 원인: 런타임 초기화 + 코드 다운로드
  • 해결: esbuild 번들 & minify, Provisioned Concurrency(PC), VPC ENI 최적화

6‑2. 서브넷·ENI 점유

  • VPC Subnet IP 개수 제한 → 대규모 동시 실행 시 ENI 부족 오류
  • 해결: PC 수 제한, VPC Endpoint for S3 사용, 필요 없는 VPC 연결 제거

6‑3. S3 퍼블릭 액세스 보안

  • 퍼블릭 접근이 필요하다면 버킷 정책으로 최소 GET 만 허용, 액세스 로그 활성화

✍️ 마무리하며

지금까지 Lambda Invoke + S3 조합으로 이미지 파이프라인을 서버리스 아키텍처로 옮기는 과정을 살펴봤습니다. 전통적인 EC2 배치 작업에 비해 

  • 비용 – 쓰는 만큼만 과금, 대기 시간 0원
  • 운영 부담 – 서버 패치·오토스케일링·로그 롤링에서 해방
  • 확장성 – 수백 RPS 이벤트도 자동으로 동시 실행

이라는 이점을 가져갈 수 있었습니다.

다만 서버리스는 만능 열쇠가 아니며, 콜드 스타트·ENI 할당·퍼블릭 액세스 설정 등 새로운 운영 이슈가 생깁니다. 이 글에서 정리한 

  • esbuild 번들·minify로 코드 경량화
  • Provisioned Concurrency로 지연 제어
  • VPC Endpoint for S3로 ENI 소모 최소화
  • 세분화된 IAM·버킷 정책으로 최소 권한 유지

같은 베스트 프랙티스를 적용한다면 대부분의 문제를 예방할 수 있습니다.


참고 자료 & 공식 문서

주제링크
AWS Lambda Best Practiceshttps://docs.aws.amazon.com/lambda/latest/dg/best-practices.html
AWS S3 Public Access Blockhttps://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html
Serverless Framework Docshttps://www.serverless.com/framework/docs/
Lambda Provisioned Concurrencyhttps://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html
profile
일하며 겪은 문제를 나눠요

0개의 댓글