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 트랜잭션과 함께 관리 | 트랜잭션 일관성, 백업 단순 | 스토리지 비용·성능 저하, 대용량 부적합 |
: Spring에서 제공하는 MultipartFile
인터페이스를 이용해 서버가 클라이언트 파일 스트림을 수신한 뒤 S3로 전달하는 전통적 방식
-
클라이언트 → WAS :
POST /upload
(multipart/form‑data) 요청 전송 -
WAS : 업로드 파일을
/tmp
같은 임시 디렉터리에 기록 -
WAS → S3 : AWS SDK
PutObject
호출로 파일 전송 - WAS → 클라이언트 : 업로드 성공 JSON 응답
-
클라이언트 → WAS :
GET /images/{id}
요청 -
WAS → S3 → WAS → 클라이언트 :
GetObject
후 이미지 스트림 반환
옵션 | 선택 이유 | 장점 | 단점 |
---|---|---|---|
AWS S3 | AWS 서비스(CloudFront·Lambda 등)와 자연스러운 연계 | 무제한 스토리지, 버전 관리, 라이프사이클 정책 | 전송·요청량에 따라 비용 증가 |
Firebase Storage | Google Auth·FCM 등 모바일 생태계 친화적 | 모바일 SDK 편리, 실시간 권한 제어 | 서울 리전 부재, AWS↔GCP 교차 트래픽 비용 |
전용 이미지 서버 | EC2 + Nginx·Thumbor 등 완전 커스텀 | 변환·캐시 로직 자유도 높음 | 인프라·보안·스케일 직접 관리 |
Database (BLOB) | RDB 트랜잭션과 함께 관리 | 트랜잭션 일관성, 백업 단순 | 스토리지 비용·성능 저하, 대용량 부적합 |
방식 | 데이터 흐름 | 장점 | 단점 |
---|---|---|---|
MultipartFile | 클라이언트 → WAS 메모리/디스크 → S3 | 구현 간단, 10 MB 이하 파일 다수에 적합 | WAS I/O·메모리 부담 |
Stream 업로드 | 클라이언트 → InputStream → S3 | 서버 메모리 거의 0, 폼 데이터 불필요 | 진척도 표시·재시도 로직 직접 구현 |
Pre-Signed URL | 클라이언트 → S3 (서버는 URL 발급만) | 서버 트래픽 0, 대용량·모바일 업로드 최적 | 클라이언트 구현 필요, 만료·범위 설정 필수 |
: Spring에서 제공하는 MultipartFile
인터페이스를 이용해 서버가 클라이언트 파일 스트림을 수신한 뒤 S3로 전달하는 전통적 방식
MultipartFile 업로드 방식
-
클라이언트 → WAS :
POST /upload
(multipart/form‑data) 요청 전송 -
WAS : 업로드 파일을
/tmp
같은 임시 디렉터리에 기록 -
WAS → S3 : AWS SDK
PutObject
호출로 파일 전송 - WAS → 클라이언트 : 업로드 성공 JSON 응답
-
클라이언트 → WAS :
GET /images/{id}
요청 -
WAS → S3 → WAS → 클라이언트 :
GetObject
후 이미지 스트림 반환
클라이언트가 파일을 업로드했을 때 WAS(Tomcat)
가 해당 파일을 임시 디렉터리에 저장후 S3에 업로드
장점 | 단점 |
---|---|
구현이 가장 간단, 튜토리얼·레퍼런스가 풍부 | 서버 디스크 용량 의존·I/O 부하, 대용량 파일 실패 위험 |
-
클라이언트 → WAS :
POST /upload
(stream) 요청 -
WAS → S3 :
InputStream
을 즉시 파이프하여PutObject
- S3 → WAS → 클라이언트 : 업로드 결과 200 응답
-
클라이언트 → WAS :
GET /images/{id}
-
WAS → S3 → WAS → 클라이언트 :
GetObject
이미지 반환
장점 | 단점 |
---|---|
서버 디스크·메모리 부담이 매우 작음 | 클라이언트 업로드 속도에 따라 실패 가능, 업로드 동안 서버 커넥션 점유(최대 50개 제한) |
AWS Multipart 업로드 방식
-
클라이언트 → API :
POST /images/presign
(파일명·MIME 등 전달) -
API → 클라이언트 :
PUT
Presigned URL(만료 5분) + 공개 조회 URL 반환 -
클라이언트 → S3 : Multipart
PUT
파트 전송 -
클라이언트 → S3 :
CompleteMultipartUpload
호출 -
S3 → SQS → Lambda → DB :
ObjectCreated
이벤트로 메타데이터 INSERT -
클라이언트 → CloudFront :
GET <https://cdn.example.com/user/>...
- CloudFront → S3 (캐시 miss) → CloudFront → 클라이언트 : 이미지 다운로드 완료
사용자에게 업로드 진행 사항을 알려줄 수 있다.
장점 | 단점 |
---|---|
서버 트래픽 0, 대용량·모바일 환경에 최적, 업로드 진행률 제공 | 구현 플로우 복잡, S3에 의존해 다른 스토리지로 교체 난이도 ↑ |
- 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 구현
- 파트 크기별 업로드 속도 비교: 8 MB vs 16 MB vs 32 MB
- 서명 URL TTL별 CloudFront 캐시 hit-rate 측정: 1 분 vs 5 분 vs 30 분
- 모바일 네트워크(지하철 LTE/5G)에서 파트 오류율 수집 및 적응형 파트 크기 적용