내가 여태까지 참여했던 프로젝트들은
S3에 업로드할 파일이라고 한다면 700KB 정도 되는 이미지 혹은 문서가 대부분이었다
크다고 해봤자 1MB 정도였으니 서버 입장에서 큰 부담은 없었다
하지만 지금 참여하고 있는 프로젝트는 교육 자료를 업로드해야 하다 보니 용량이 큰 강의 파일을 처리해야 했다
500MB 정도의 파일이었다
500MB는 일반적인 클라이언트 - 서버 간 파일 업로드에서 큰 용량이다
특히 서버 입장에서는 이를 한 번에 처리하면 네트워크 대역폭, CPU, I/O 등에 과부하가 발생할 수 있다
이를 해결하기 위해 AWS S3의 Presigned URL 방식을 도입했다.
기존 업로드 API 로직은
1. 클라이언트에서 서버로 파일을 전송
2. 서버에서 파일을 S3에 업로드한 뒤 Image URL 반환
이다.
이 방식은 작은 파일(1MB 이하) 업로드에는 적합했지만, 대용량 파일(500MB) 에서는 서버에 꽤 큰 부담이 되었다
강의의 썸네일 이미지나 참고 문서 파일을 저장하는 구간을 개발할때는 괜찮았다.
하지만 강의 영상을 업로드하는 페이지를 개발할때 ECS 프리티어 환경에서 기존 API를 통해 500MB 파일을 전송했더니 CPU 사용량이 100%에 도달하면서 서버가 응답하지 않는 상태가 되어버린 것이다...omg
급한대로 서버 용량을 늘리고 헬스체크 시간을 확인해 해결했지만, 이러한 조치는 본질적인 해결책이 아니라는 생각이 들었다
추후 개발이 완료되어 실제로 서비스를 운영하면, 여러 사용자가 동시에 대용량의 강의 파일을 업로드 하게 될 것이다.
그런 상황에서 과부하가 올 때마다 계속해 서버 용량을 올리는것은 운영 비용이 계속 증가하게 되므로 너무 비효율적인 방식인 것 같았다.
그래서 서버의 부하를 줄이면서도 클라이언트가 안전하게 파일을 업로드할 수 있는 방법을 찾아봤고, AWS S3의Presigned URL을 활용한 방식이 적합하다고 판단했다
새롭게 개발한 API 는
AWS S3의 Presigned URL 을 활용한다
1. 클라이언트에서 서버로 파일명과 파일타입만 전달
2. 서버는 파일명과 파일 타입에 기반해 클라이언트가 S3로 직접 업로드 할 수 있는 Presigned Url 을 생성하고 반환
3. 클라이언트는 해당 URL에 PUT 요청을 보내 파일을 S3에 직접 업로드
이렇게 해서 서버에는 직접적인 파일을 받지않아 cpu에 대한 부담과 시간을 줄일 수 있을 뿐만 아니라,
서버가 파일 데이터에 접근을 하지 않기 때문에 민감한 데이터를 보호할 수 있다.
async generatePresignedUrl(
fileName: string,
fileType: string,
): Promise<{ url: string; key: string }> {
const bucketName =
this.configService.getOrThrow<string>('BUCKET_NAME');
const fileKey = `uploads/${Date.now()}_${fileName}`;
const params = {
Bucket: bucketName,
Key: fileKey,
ContentType: fileType,
};
try {
const url = await getSignedUrl(this.s3, new PutObjectCommand(params), {
expiresIn: 5 * 60,
});
return { url, key: fileKey };
} catch (error) {
throw new InternalServerErrorException('PreSigned URL 생성 실패');
}
}
expiresIn 은 Presigned URL 의 유효기간이다
현재는 보안 강화를 위해 짧게 5분으로 설정했지만 상황에 따라 조정 가능하다
DB에 file url 저장하는 방식과, Presigned URL 도입으로 개선된 부분은 다음 글에 이어서 작성 할 예정이다.
S3에 업로드하는 시간 자체를 줄일 수 있는 '멀티파트 업로드' 라는 방법도 있다고 한다
파일을 여러 조각으로 나누어 동시에 업로드한 뒤 병합하는 방식이다
멀티파트 업로드 방식과 Presigned Url 방식을 동시에 사용할 수 도 있다고 하니 다음 개발 때 적용해보고싶다!!
'오류 해결 > AWS' 카테고리의 다른 글
[AWS] IAM 계정 권한 설정 했는데도 리소스 접근 불가일 때 (1) | 2025.06.12 |
---|---|
[S3] Presigned URL 사용해보기 2 / 고용량 파일 업로드 시 CPU 사용량 100% 혹은 서버 터질 때 (0) | 2024.12.10 |
[RDS/MySQL] RDS DB 연결 안될때, 연결 시간초과 오류 뜰 때 (1) | 2024.06.17 |
[S3] 업로드한 이미지가 안열릴때, 객체 url 누르면 권한없음 흰 창 뜰 때 (0) | 2024.06.17 |