이미지 처리
사내 서비스 서버 부하는 대부분의 비중이 이미지에서 나옵니다. 큰 사이즈의 이미지가 연속해서 올라오면 뒤에 들어오는 클라이언트의 요청은 계속 딜레이되고 결국 실패했다고 나오는 현상이 많이 발생했습니다.
그리고, 대부분의 cs가 옷 생성 시 응답이 없거나 실패했다는 종류의 리뷰였습니다. 저희 서비스 아키텍처의 문제를 인식 및 정의를 하고, 어떻게 아키텍처를 개선해나갔는지를 공유하려고 합니다.
문제점
- 전달과정 비효율 (클라이언트-서버-AWS S3 base64로 이미지 전달)
- 네트워크 비용 매우 비효율
옷 생성 요청시 용량이 5~10MB짜리도 많이 들어옵니다.
옷 생성 api만 10분당 500~1000개 옷 생성을 요청
(최대치) 1000 * (최대치) 10MB = 10GB 처리해야함
아래는 10분당 옷 생성 요청 수 막대그래프입니다. 10분마다 1000개의 옷을 생성하는데
5개 서버(2core, 메모리 6GB)가 나눠서 처리한다고 가정하면 옷 이미지 업로드하는 것만 2GB(10GB/5 서버)씩 이상의 메모리 차지하게 됩니다. 아래는 10분간 요청 수이지만 1분 동안 급격하게 요청하는 경우에는 문제가 생길 수 있고, 옷 배경제거, 기타 이미지 서비스 api까지 포함하면 서버가 충분히 죽을 수 있습니다.
기존 로직 정리
- base64 형태로 서버 전달
- 서비스 서버는 배경제거 서버로 proxy 역할
- 이미지 resize - s3 업로드 - 디비 저장을 모두 이미지를 주고 받으며 인라인으로 처리
문제점 인식
- 일차적으로는 이미지가 binary가 아닌 base64로 전달한다는 점 입니다. 이 base64는 일반적인 ASCII 문자로 변환하고 패딩이 들어가기에 33% 정도 크기가 커진다고 합니다.
- 목적은 이미지를 배경제거 서버나 이미지 resize, S3 업로드를 하기 위해서 서비스 서버를 거쳐서 들어간다는 점 입니다.
해결 방안
여러 이미지 업로드하는 서비스를 조사했더니 개선할 수 있는 아키텍쳐들이 많이 있었습니다.
- aws s3는 presigned URL이라는 것을 지원해줍니다. 이는 클라이언트에서 직접 secret key 없이도 get이나 put을 할 수 있는 url을 한정된 시간동안 열어줍니다. 이는 서버가 이미지를 직접 올릴 필요가 없어진다는 큰 장점이 있습니다.
- 이미지를 직접 보내지 않고, url을 통해서 전달하면 불필요한 네트워크 통신 비용이 없어질 것 입니다.
- 추가적으로 당근 마켓이나 비트윈, AWS 사례에서 실시간 리사이징에 대한 아키텍쳐를 통해서 s3 저장비용을 획기적으로 개선한 사례가 많이 있어 적용하려고 했습니다. 사용하지 않을 썸네일 이미지를 계속해서 저장하게 되면 월 유지비용이 누적됩니다. 그에 비해 실시간 리사이징에 쓰이는 람다 엣지에 비용은 굉장히 싼 편 입니다.
가운데 숫자가 사용량이고, 가장 오른쪽이 비용(달러)이다. 매우 저렴한 걸 알 수 있다.
업로드 및 실시간 이미지 리사이징 방식
클라이언트는 서버에서 presigndURL를 받아 S3에 직접 업로드합니다. 그리고 이 이미지를 조회하는 클라이언트는 Clounfront에서 캐시 유무를 확인하고, 오리진(s3)에서 이미지를 응답받을 때, cloudfront에서 연결해놓은 lambda edge가 트리거되면서 리사이징을 하고, 캐시를 저장한 후 클라이언트로 이미지를 내려줍니다.
개선 방식
- 배경 제거와 옷 생성에 전달되는 이미지를 클라이언트가 직접 s3에 전달하여 서버 부하를 낮췄고, 불필요한 썸네일 이미지를 보관하지 않고 실시간 리사이징을 함으로써, 옷 생성 latency가 대폭 줄어들었습니다. (1.5s -> 약 58ms)
추가 개선 사항