이미지 최적화 도입기 feat. Nextjs
NextJS에는 Image 컴포넌트를 통해 이미지 최적화를 해주고 있다. 더보기
물론 이 좋은 기능을 쓰면 개발자 경험으로 따지면 최상이다. 하지만 서비스를 운영해야되는 운영자(돈없는 학생)의 입장으로써 비용도 같이 최적화 해야된다.
인프라는 전적으로 Vercel을 사용하고 있는데 NextJS의 Image Optimization을 사용하는데 아이러니하게도 Vercel이 여기서 과금을 때린다.
처음에는 그냥 막연하게 쓰면 되겠지 했는데, Hobby Plan 기준 20일만에 20%를 나 혼자서 사용했다는것이다.
Vercel의 Image Optimization 과금표는 다음과 같다.
과금표를 살펴보면 Pro Plan 기준 한달에 5000개의 이미지를 최적화해주고 초과 요금으로 1000개당 약 6800원을 뜯으간다.
실제 운영했다고 가정했을때 조금만 흥해도 부담스러워질수도 있겠다 싶었다.
여기서 잠깐 프로젝트 인프라를 확인하고 가자.
만약 NextJS의 Image를 사용하게되면 인프라 구조는 다음과 같다.
Aws CloudFront에서 Vercel이 이미지를 받아와 최적화를 한다음 Vercel에서 Browser로 이미지를 내려준다.
그리고 이 때 Vercel에서 두 가지 비용이 발생한다.
- 이미지 최적화 비용 Source Images 비용
- 최적화된 이미지에 대한 트래픽 비용 Fast Data Transfer 비용
토이 프로젝트 수준에서는 괜찮은 가격 같지만 그래도 좀 비싸보인다.
과감히 NextJS Image 기능을 버리고 다른 방식을 탐색해보았고,
제일 먼저 떠오른건 클라이언트에서 압축을 방법이었는데, 모바일 환경일 경우 렉이 너무 심했다.
→ 04. 05. 클라이언트에서 압축하는 짓은 하지말자
이후 고안해낸 방법은 유저가 s3에 이미지를 업로드 했을 때 AWS Lambda로 이미지 resize를해서 새로 저장하는 방법이었다. 이 방법을 채택할 경우, 인프라 구조는 다음과 같다.
이 방법은 사용자가 CloudFront에서 직접 가져오므로 위에서 언급한 두가지 비용이 발생하지 않는다. 다만, AWS Lambda와 S3가 하나 더 늘어났으므로 그에 대한 비용이 새로 생겼다.
S3는 Post, Put 요청에 대해서 프리티어 2000건 초과시 1000건당 약 6원이고 아 5000건이면 약 18원밖에 안나온다. AWS 비용
Lambda는 512mb x86 환경에서 사용한다고 했을 때, 이미지 처리가 약 3초가 걸린다고 가정하면 5000개의 이미지를 처리 했을 때 총 15000초이고 비용은 170원이다.
근데 이 마저도 프리티어에서 40만초는 매달 무료로 사용하게 해준다. 스토리지 비용 및 요청 건당 비용이 있긴한데 토이 프로젝트 수준에서는 무시해도 될만한 정도이다.Lambda 비용
도합 1000원도 안되는 혜자 aws이다.
비용은 매우 마음에 드나, 구축하기전에 우려사항이 하나 있었는데, 그림 4에서 사용자가 s3 Origin에 이미지를 업로드하면 s3 Compress에 등록하기까지 3초가 걸린다. 이 때 사용자는 업로드 직후 3초동안 이미지를 확인할 수 없는데, 이는 사용자 경험을 해치기에 해결 방안 모색이 필요했다. 여기 댓글에서 찾을 수 있었는데, 클라이언트에서 S3 Compress의 이미지 요청이 실패했을때 S3 Origin의 이미지를 보여주는 방식이다. 이미지 용량이 큰 S3 Origin에 다시 요청한다는게 썩 내키진 않았지만 그래도 이 방법 말고는 떠오르지가 않아서 진행해보았다.
위 영상은 업로드 직후 compress 이미지 로딩이 실패되어 origin 이미지로 대체되는 영상이다.
중간에 이미지 깨짐 아이콘이 보이는데 Chrome에서는 css로 해결가능하지만 safari에선 해결할 방법이 안보였다. div로 바꾸는 정도..? 하다하다 안되서 이미지 로딩에 실패하면 3초뒤에 다시 refetching 해오는 방식으로 구현해봤는데 성공은 했으나 lambda에서 3초만에 처리가 안되는 이미지도 간혹 있었고, 그냥 별로였다. 그러던 도중 reddit에 한 글을 보게되는데. 댓글에 지리는 사이트를 확인해볼 수 있었다.
사이트는 NextJS의 Image Optimization 같이 이미지 압축 및 최적화를 무료로 제공해준다는것이다. 사용법은 Url에 내가 최적화하고자 하는 이미지 url을 삽입해주면 된다.
<Image
unoptimized
src={`https://images.weserv.nl/?url=${image.originUrl}&w=800&h=800`}
alt=""
/>
의심스러워서 진짜 비용을 뜯어가지 않는지 확인해본 결과,
Furthermore, there is a request limit per visitor IP for uncached requests, which is 2500 images per 10 minutes, after which the IP-address will be blocked for 1 hour.
방문자(IP) 당 10분에 캐시되지 않은 이미지를
2500번 요청할때 1시간동안 막힌다고 한다. (괜찮은데..?)
We cache images in different ways, depending on the rate of requests, no more than 31 days, and most often at least 7 days.
또한 자체적으로 캐시 히트 비율에 따라 최소 7일에서 최대 31까지 저장해준다고 한다.
보자마자 aws 구축해놓은거 다 다운시키고 적용해보았다.
실제 업로드하고 결과를 봤을 때, 괜찮은 성능을 보인다.
결론적으로 weserv.nl를 도입하면서 Vercel에서 발생하는
- 이미지 최적화 비용
- 최적화된 이미지에 대한 트래픽 비용
을 아낄 수 있었다.