S3 이미지 업로드 방식 비교 - lets-go-trip/treaXure-backend GitHub Wiki

참고 자료

- 참고한 강의 자료: [10분 테코톡] 백호, 망쵸의 Spring Boot와 AWS를 이용한 이미지 업로드 및 최적화

- 모든 이미지 출처: Spring Boot에서 S3에 파일을 업로드하는 세 가지 방법 | 우아한형제들 기술블로그

이미지를 어디에 올릴까?

옵션 선택 이유 장점 단점
AWS S3 AWS 서비스(CloudFront·Lambda 등)와 자연스러운 연계 무제한 스토리지, 버전 관리, 라이프사이클 정책 전송·요청량에 따라 비용 증가
Firebase Storage Google Auth·FCM 등 모바일 생태계 친화적 모바일 SDK 편리, 실시간 권한 제어 서울 리전 부재, AWS↔GCP 교차 트래픽 비용
전용 이미지 서버 EC2 + Nginx·Thumbor 등 완전 커스텀 변환·캐시 로직 자유도 높음 인프라·보안·스케일 직접 관리
Database (BLOB) RDB 트랜잭션과 함께 관리 트랜잭션 일관성, 백업 단순 스토리지 비용·성능 저하, 대용량 부적합

1. MultipartFile 업로드

: Spring에서 제공하는 MultipartFile 인터페이스를 이용해 서버가 클라이언트 파일 스트림을 수신한 뒤 S3로 전달하는 전통적 방식

MultipartFile 업로드 방식

MultipartFile 업로드 방식
  1. 클라이언트 → WAS : POST /upload (multipart/form‑data) 요청 전송
  2. WAS : 업로드 파일을 /tmp 같은 임시 디렉터리에 기록
  3. WAS → S3 : AWS SDK PutObject 호출로 파일 전송
  4. WAS → 클라이언트 : 업로드 성공 JSON 응답
  5. 클라이언트 → WAS : GET /images/{id} 요청
  6. WAS → S3 → WAS → 클라이언트 : GetObject 후 이미지 스트림 반환

이미지를 어디에 올릴까?

옵션 선택 이유 장점 단점
AWS S3 AWS 서비스(CloudFront·Lambda 등)와 자연스러운 연계 무제한 스토리지, 버전 관리, 라이프사이클 정책 전송·요청량에 따라 비용 증가
Firebase Storage Google Auth·FCM 등 모바일 생태계 친화적 모바일 SDK 편리, 실시간 권한 제어 서울 리전 부재, AWS↔GCP 교차 트래픽 비용
전용 이미지 서버 EC2 + Nginx·Thumbor 등 완전 커스텀 변환·캐시 로직 자유도 높음 인프라·보안·스케일 직접 관리
Database (BLOB) RDB 트랜잭션과 함께 관리 트랜잭션 일관성, 백업 단순 스토리지 비용·성능 저하, 대용량 부적합

S3에 어떻게 이미지를 업로드할까?

방식 데이터 흐름 장점 단점
MultipartFile 클라이언트 → WAS 메모리/디스크 → S3 구현 간단, 10 MB 이하 파일 다수에 적합 WAS I/O·메모리 부담
Stream 업로드 클라이언트 → InputStream → S3 서버 메모리 거의 0, 폼 데이터 불필요 진척도 표시·재시도 로직 직접 구현
Pre-Signed URL 클라이언트 → S3 (서버는 URL 발급만) 서버 트래픽 0, 대용량·모바일 업로드 최적 클라이언트 구현 필요, 만료·범위 설정 필수

1. MultipartFile 업로드

: Spring에서 제공하는 MultipartFile 인터페이스를 이용해 서버가 클라이언트 파일 스트림을 수신한 뒤 S3로 전달하는 전통적 방식

MultipartFile 업로드 방식

MultipartFile 업로드 방식

  1. 클라이언트 → WAS : POST /upload (multipart/form‑data) 요청 전송
  2. WAS : 업로드 파일을 /tmp 같은 임시 디렉터리에 기록
  3. WAS → S3 : AWS SDK PutObject 호출로 파일 전송
  4. WAS → 클라이언트 : 업로드 성공 JSON 응답
  5. 클라이언트 → WAS : GET /images/{id} 요청
  6. WAS → S3 → WAS → 클라이언트 : GetObject 후 이미지 스트림 반환

임시 디렉토리 사용 과정

클라이언트가 파일을 업로드했을 때 가 해당 파일을 임시 디렉터리에 저장후 S3에 업로드

클라이언트가 파일을 업로드했을 때 WAS(Tomcat)가 해당 파일을 임시 디렉터리에 저장후 S3에 업로드

장점 단점
구현이 가장 간단, 튜토리얼·레퍼런스가 풍부 서버 디스크 용량 의존·I/O 부하, 대용량 파일 실패 위험

2. Stream 방식

image.png

  1. 클라이언트 → WAS : POST /upload (stream) 요청
  2. WAS → S3 : InputStream 을 즉시 파이프하여 PutObject
  3. S3 → WAS → 클라이언트 : 업로드 결과 200 응답
  4. 클라이언트 → WAS : GET /images/{id}
  5. WAS → S3 → WAS → 클라이언트 : GetObject 이미지 반환
장점 단점
서버 디스크·메모리 부담이 매우 작음 클라이언트 업로드 속도에 따라 실패 가능, 업로드 동안 서버 커넥션 점유(최대 50개 제한)

3. Presigned URL (AWS Multipart Upload)

AWS Multipart 업로드 방식

AWS Multipart 업로드 방식

  1. 클라이언트 → API : POST /images/presign (파일명·MIME 등 전달)
  2. API → 클라이언트 : PUT Presigned URL(만료 5분) + 공개 조회 URL 반환
  3. 클라이언트 → S3 : Multipart PUT 파트 전송
  4. 클라이언트 → S3 : CompleteMultipartUpload 호출
  5. S3 → SQS → Lambda → DB : ObjectCreated 이벤트로 메타데이터 INSERT
  6. 클라이언트 → CloudFront : GET <https://cdn.example.com/user/>...
  7. CloudFront → S3 (캐시 miss) → CloudFront → 클라이언트 : 이미지 다운로드 완료

업로드할 파일을 작은 part로 나누어 각 부분을 개별적으로 업로드

사용자에게 업로드 진행 사항을 알려줄 수 있다.

image.png

장점 단점
서버 트래픽 0, 대용량·모바일 환경에 최적, 업로드 진행률 제공 구현 플로우 복잡, S3에 의존해 다른 스토리지로 교체 난이도 ↑

2. 구현 체크리스트

  • URL 만료: 5 분 이하 설정, Multipart Upload 파트는 15 분 허용
  • 정책 제한: content-length-range·content-type 조건 포함해 남용 차단
  • Abort 처리: 오류·취소 시 AbortMultipartUpload 호출 및 DLQ로 감시
  • 버킷 보안: Public Access Block ON + CloudFront OAC 연동
  • 다운로드 보호: CloudFront Signed Cookie 또는 WAF Referer 룰 적용
  • 모니터링: S3 RequestMetrics + CloudTrail DataEvent + Cost Anomaly Detection
  • 클라이언트 검증: 파트 재시도·ETag 검증·진행 바 UI 구현

3. 실험 항목(추후)

  • 파트 크기별 업로드 속도 비교: 8 MB vs 16 MB vs 32 MB
  • 서명 URL TTL별 CloudFront 캐시 hit-rate 측정: 1 분 vs 5 분 vs 30 분
  • 모바일 네트워크(지하철 LTE/5G)에서 파트 오류율 수집 및 적응형 파트 크기 적용
⚠️ **GitHub.com Fallback** ⚠️