
사이드 프로젝트를 수행하면서, 미션과 인증글이 생성될 때 이미지 파일을 저장하는데, 서버 리소스 절약, 서버 부하 감소를 이유로 presignedUrl을 적용하게 되었다.
기존 이미지 파일 저장 흐름

기존에는 클라이언트로부터 API 요청이 들어오면, 다른 리소스를 저장하는 것처럼 당연하게도 서버가 s3에 업로드하고 imageUrl을 저장했다.
파일 업로드는 JSON 데이터를 주고 받는 일반 API 요청에 비해 훨씬 큰 부하를 발생시키는 작업이다.
클라이언트가 파일 업로드 요청을 보내고, 서버가 S3에 업로드까지의 시간이 길어지므로, 응답 시간이 증가한다. 이는 커넥션 풀이 늘어지는 것에 영향을 줄 수 있고, 병목 현상의 원인이 될 수 있다.
클라이언트가 업로드한 파일이 서버를 거쳐 s3로 전송되는 과정에서 불필요한 네트워크 대역폭이 소모된다. 이는 다른 클라이언트 요청 처리에 필요한 대역폭을 줄이는 결과를 초래할 수 있다.
이러한 문제로, 대안점을 찾다가 presignedUrl을 도입하게 되었다.
PresignedUrl 이란 ❓
다른 사람이 AWS 보안 자격 증명이나 권한이 없어도 Amazon S3 버킷에 객체를 업로드할 수 있게 허용해주는 URL입니다. S3의 접근 정책이나 권한 정책과 관계없이 특정 유효기간에 S3에 PUT, GET이 가능하다.
Pre-Signed Url을 통해 허용된 기간과 범위안에서만 접근이 가능하게 제어할 수 있다. 이를 통해 무단 엑세세를 방지하고, 보안을 강화할 수 있다.
Pre-Signed Url을 통해 클라이언트에게 파일 업로드 권한 url을 부여해, 클라이언트가 서버 리소스를 거치지 않고 S3에 직접 파일 업로드를 수행할 수 있다. 이를 통해 서버 리소스를 절약하고, 불필요한 네트워크 대역폭을 소모하지 않는 성능상 이점을 누릴 수 있다.
PresignedUrl 흐름

build.gradle에 AWS SDK 의존성 추가 🔧

S3config 파일 작성
s3에 접근권한이 있는 accessKey, secretKey를 기반으로 credential을 만들어 S3Presigner 객체를 생성한다.

ImageService 작성
config파일에서 명시한 presigner bean 의존성을 추가한다.
이미지 업로드, 조회를 위한 get과 put 방식의 presignedurl을 생성하는 메서드를 작성한다.

ImageController 작성
샘플코드로 작성해보았다.

흐름 ⏳
먼저 클라이언트는 업로드하고자 하는 파일명을 requestParam으로 api를 요청한다.
그럼 서버는 s3에 서명을 인가받은 url 경로를 응답해준다.

다음으로, 클라이언트는 서버로부터 응답받은 url에 binary타입으로 이미지를 첨부해 put 요청을 날린다.

마지막으로, 클라이언트는 업로드한 파일 경로를 서버에게 전달해, 서버는 해당 경로를 DB에 저장한다.
