

요즘 아이폰을 기준으로 사진을 찍으면 대략 2MB~8MB 사이로 굉장히 용량이 크다.
물론 덕분에 우린 더 고화질의 사진을 볼 수 있게 해주니까 분명 좋기 때문에
2MB ~ 8MB를 렌더링 시켜주는 게 그렇게 무리는 아니다.
하지만 이렇게 리스트뷰로 보이는 데서 개당 2MB~8MB 정도되는 이미지를 렌더링하면 어떨까?
메모리를 사용하는데 무리가 됨은 물론, 어차피 작아서 고화질을 체감하기도 힘들다.
이렇게 잘 보이지도 않는데 고화질을 그대로 렌더링하는 건 분명 굉장히 비효율적이다. 때문에 우리 팀에서 리스트 뷰에서는 썸네일을 받아서 렌더링하도록 했다.
사진을 다운샘플링하는 연산은 굉장히 많은 리소스를 사용한다.
때문에 기존의 비즈니스로직을 동작시켜야하는 웹 어플리케이션에서 이를 병행하는 건 무리가 있다고 판단했다.
그렇게 되면 이제 두 가지 선택지가 생긴다.
이 중 우리는 서버리스를 선택했다.
Cold Start 문제 
Cold Start는 간단히 설명하면 서버리스가 시작되기 위해 자원을 할당(컨테이너 구동, 런타임 초기화, 컴파일) 하는 시간 때문에 응답에 지연이 발생할 수 있는 문제가 있다.Cold Start 자체는 매번 발생하는 문제가 아닐 뿐만 아니라, 썸네일 자체는 조금 지연되어서 저장되고 로직을 수행하는데 큰 문제가 없다. (썸네일이 저장되어 있지 않는 레코드는 원본 이미지 URL을 반환하는 방법으로 해결가능)
사진을 위한 IO 작업은 굉장히 많은 리소스를 사용한다.
사실 거기까진 우리의 예측이었고, 현실적으로 메모리를 얼마나 사용할까 자체는 잘 알지 못했다.
하지만 한 번의 실수를 통해 나온 결과로 메모리 사용량이 엄청나다는 걸 알 수 있었다.
위 사진은 서버리스 테스트 중, 실수로 로직이 재귀적으로 돌게 만들어버려서 1분정도 동안 200회 정도의 다운샘플링 연산을 시켜버린 결과인데 150GB에 달하는 메모리를 썻다는 것을 알 수 있다.
서버리스를 사용하기 위해서는 하나의 함수 형태를 등록해주면 된다. Node.js, Python, Java 등등 몇 가지 런타임을 제공하지만, 우리는 파이썬을 선택했다.
그렇게 최종적으로 이렇게 소스코드를 등록할 수 있다.

인터넷이 연결되면 외부 모듈이 필요하면 이렇게 requirements.txt 와 main.py 를 압축해서 올려도 사용할 수 있다.

import os
import boto3
from PIL import Image
service_name: str = 's3'
endpoint_url: str = 'https://kr.object.ncloudstorage.com'
def downsample_image(input_path: str, output_path: str,
downsample_size: tuple[int, int] = (500, 500)):
if not os.path.exists(os.path.dirname(output_path)):
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with Image.open(input_path) as img:
downsampled_img: Image.Image = img.resize(
downsample_size, Image.Resampling.LANCZOS)
downsampled_img.save(output_path)
def main(args):
bucket_name: str = args['container_name']
thumbnail_bucket: str = f"{args['container_name']}-thumbnail"
object_name: str = args['object_name']
s3: boto3 = boto3.client(
service_name,
endpoint_url=endpoint_url,
aws_access_key_id=args['access_key'],
aws_secret_access_key=args['scret_key'],
)
object_path: str = f"./{object_name}"
thumbnail_path: str = f"./thumbnail/{object_name}"
s3.download_file(bucket_name, object_name, object_path)
downsample_image(object_path, thumbnail_path)
s3.upload_file(thumbnail_path, thumbnail_bucket, thumbnail_path)
return args
requirements.txtboto3==1.29.5
botocore==1.32.5
jmespath==1.0.1
Pillow==10.1.0
python-dateutil==2.8.2
s3transfer==0.7.0
six==1.16.0
urllib3==2.0.7
$ zip -r ds.zip __main__.py requirements.txt


6MB의 사진을 serverless라는 버킷에 업로드Cold Start가 안걸린 상태Cold Start가 걸리면 지연시간이 꽤 걸리는 경우도 있었다.serverless-thumbnail이라는 버킷에 해당 사진의 썸네일이 48KB의 사이즈로 업로드 됨