안녕하세요 똑똑한 개발자에서 백엔드 개발을 하고 있는 김영환 입니다. 웹 개발을 하다보면 다량의 이미지를 업로드해야되는 경우가 생김니다. 서로 다른 이미지 크기와 용량으로 사이트 업로드의 시간을 늦출수있는 경우가 있습니다. 그런 경우를 대비해서 이미지 리사이즈를 시켜준뒤 저장하는 방법에 대해 알아보겠습니다.

기존의 이미지 처리 방식 resize(1)

  • 업로드 시에 이미지를 리사이징하거나 렌더링 해야하기 때문에 연산이 많아진다 (서버 사양이 좋아야한다.)
  • 다양한 해상도의 이미지를 저장하기 때문에 스토리지 비용이 원본 하나 저장할 때 보다 증가한다.
  • 이미지 스토리지 마이그레이션 시간과 비용이 장난이 아니다.

이러한 이유때문에 기존의 이미지 처리 방식은 지양하고, 온디맨드 이미지 리사이징 방식을 이용한다고 한다. resize(3)

온디맨드 이미지 리사이징은 이미지 로딩 시 필요할 때만 해상도 또는 렌더링하여 문제를 해결하는 방식으로 접근합니다. 온디맨드라는 단어에 맞게 필요할 때(수요)만 그 때 마다 문제를 해결하자는 방식입니다.

온드맨드 이미지 리사이징 방식의 장점

  • 원본 이미지만 저장하기 때문에 스토리지 비용이 상대적으로 감소한다.
  • 이미지 업로드의 연산이 상대적으로 가볍다.
  • 새로운 해상도의 이미지가 필요할 경우 상대적으로 해상도 대응 문제를 해결하기 쉽다.
  • 자주쓰이지 않는 해상도의 이미지를 저장할 필요가 없다.

온디맨드 이미지 리사이징 방식의 단점

  • 최초 이미지를 요청 시 이미지를 리사이징 해야 하므로 로딩이 느리다.
  • 이미지 캐싱 서버의 중요도와 의존도가 상대적으로 더 높다. Cache hit가 굉장히 중요하다. hit율이 낮으면 매번 이미지를 리사이징하므로 과부화 발생 가능성이 높다.

다양한 해상도에 대한 리사이징은 내가 지금 진행하고 있는 프로젝트에선 필요성을 느끼지 못해서 구현은 하지 않았다. resize(4)

위에서 Image Upload Server 를 자체 로직에서 처리해서 AWS S3(Image Storage)에 저장시키는 방법을 선택했다. 이유는.. 업로드할 이미지도 많지 않았고, 한번올린 해상도와 크기를 따로 줄여서 저장해줄 필요가 없었기때문에 사이즈가 커서 불필요한 용량을 차지하는 부분을 똑같은 이미지 크기로 저장해두는 작업만 진행을 하였다. python에서 pillow를 이용해서 진행하였다.

    # Product models.py
    @classmethod
    def make_thumbnail(cls, thumbnail_data, product_name):
        image_name = f'{product_name}_{str((timezone.now().strftime("%Y%m%d")))}'
        image = Image.open(thumbnail_data).convert('RGB') 
        image.load()
        image.thumbnail((400, 400), Image.ANTIALIAS) # image resize 
        output = BytesIO()
        image.save(output, format='JPEG', quality=90) # JPEG로 저장
        thumbnail = ContentFile(output.getvalue(), name=f'{image_name}.jpeg') # 사용자 지정 이미지 이름
        return thumbnail

여기서 생겨난 이슈는 상품등록하는 thumbnail image는 model를 거치면 바로 s3에 저장되는 모습을 보여주고있어서 모델에 저장되기전에 리사이징을 해야되서 django-form에서 먼저 처리해주는 작업을 추가하였다.

    # Product admin.py
    def save_form(self, request, form, change):
        thumbnail_data = form.files.get('thumbnail')
        if thumbnail_data:
            thumbnail = Product.make_thumbnail(thumbnail_data, form.cleaned_data['name'])
            form.instance.thumbnail = thumbnail

        return super().save_form(request, form, change)

마치는 말

리사이징을하고 aws s3에 저장되는 용량 차이를 확인 할 수 있었고, 이러한 과정을 서버리스를 이용해 image resize server을 구축하여 처리한다면 좀더 좋은 아키텍쳐를 구현 할 수 있을것같다. 추후에 사이드 프로젝트로 이러한 서비스로 구현해 보도록 하겠다. 기존의 리사이징 방식이나 온디맨드 리사이징 방식 둘다 어째됬든 어디선가의 서버에서는 이미지 처리를 위한 열일(?)을 해야된다는것을 배웠고, 비용적인 측면과 서버의 불필요한 리소스를 줄이기 위해 꼭 필요한 작업이라는 것을 알 수 있었다. 또한 서버에서 감당하지 못하는 대용량 이미지에 대한 처리도 구현해 보고싶다.

younghwan.kim's profile image

younghwan.kim

2021-06-30 10:35

Read more posts by this author