Firebase storage가 너무 느려요

HR·2023년 3월 23일
3

스택티콘

목록 보기
1/5
post-thumbnail

스택티콘에서는 현재 유저가 생성한 스택을 이미지로 제공하기 위해서, 아래와 같은 로직을 거치고 있다.

  1. html element를 png 파일로 변환한다.
  2. 변환된 png를 Firebase storage에 업로드 하고, url을 받아온다.
  3. 받아온 url을 유저에게 제공한다.

이렇게 firebase storage를 CDN 서버로 사용하고있다. 그런데, 이미지 링크를 통해 이미지를 불러오는 속도가 너무 느리다.
정확한 측정을 위해 3번 테스트를 진행했다.

test test test

이렇게 이미지를 단순히 서버에서 가져오는데 평균 2초가 넘는 시간이 소요되었다.
이미지가 나오는데 2초나 기다려야 한다니... 절대 쓰고 싶지 않다.

문제점 찾기

이미지 사이즈 때문일까?

이미지 사이즈는 10KB미만의 사이즈부터, 300KB가 넘어가는 사이즈까지 다양하다.
하지만 평균 사이즈는 대략 20KB ~ 30KB, 스택이 조금 많이 포함된 경우에는 60KB ~ 70KB 정도의 사이즈를 가진다.

이 테스트를 위해 기존에 300KB가 넘는 큰 사이즈의 사진을 직접 로드해봤는데, 이상한 점이 발견됐다.

굉장히 빠르다..? 이미지 사이즈의 문제는 아닌 것 같다.

그렇다면 Firebase의 문제일까?

맨 처음 2초가 넘게 걸린 이미지와 같은 이미지를 AWS S3에 올려서 테스트 해보았다.

역시 문제가 없을 정도의 속도로 로드된다.
이를 통해 firebase의 문제로 가정을 하고, firebase의 이미지가 github에 업로드 되는 과정을 파악해보기로 했다.

깃허브에서 이미지와 비디오를 업로드 하는 방법

현재 깃허브는 video와 이미지 같은 파일들을 유저가 입력한 대로 바로 렌더링 하지 않고, camo라는 프록시 서버를 거친 뒤 제공하고 있다. 이는 성능, 보안, mixed-content warning 등 다양한 이슈를 방지하기 위함이고, pipeline에 심어져있다보니 이를 우회할 수 있는 방법은 없다. 관련 문서 링크

따라서 firebase로 해결이 불가능하다면, CDN 서버를 firebase이외의 것으로 선택하는 방법으로 하기로 결정했다.

Firebase로 해결할 수 있을까?

firebase와 s3의 차이

우선 두 CDN 서버의 차이를 비교해봐야 했다.
두 경우의 이미지 링크를 우선 비교해봤다.
firebase

https://firebasestorage.googleapis.com/v0/b/{bucket 주소}/o/images%2F1678426359858?alt=media&token={엄청 긴 토큰 값}

S3

https://{bucket 주소}.s3.{bucket location}.amazonaws.com/1680536550126.png

두 주소를 보니 S3는 .png로 타입을 명시하고 있고, firebase는 파일에 대한 경로와 파일 이름에 대한 경로를 지정하고, 따로 타입을 지정해주고 있지 않다.

그러면 이에 따라 실제 네트워크 요청에서도 다른 점이 생길까?

네트워크 요청 분석


위가 firebase, 아래가 S3이다. 동일하게 png로 인식하고 있음을 알 수 있다.

추론

그렇다면, firebase storage에서 url을 추출할 때, 파일 타입을 명시해주면 해결되지 않을까?

업로드 방식 변경

기존의 html을 png로 변환해 업로드 하는 방식은 아래와 같았다.

  1. html 조각을 ref로 가져온다.
  2. ref로 가져온 html을 html-to-pngtoPng를 통해 png로 변환한다. 리턴 값은 string이다.
  3. 2에서 얻은 string을 firebase/storage의 uploadString 을 통해 업로드한다.

이를 아래와 같이 변경해보았다.

  1. html 조각을 ref로 가져온다.
  2. ref로 가져온 html을 blob으로 변환한다.
  3. 2에서 얻은 blob을 firebase/storage의 uploadBytes를 통해 업로드 한다. 이 때, 메타데이터로 content-type을 명시해준다.
const metaData = {
  contentType: 'image/png'
}
const uploadResult = uploadBytes(storageRef, imageRef, metaData);

-> firebase에 올라간 결과물과, 실제로 렌더링 하는데에 시간 변화가 없다.

storage에서의 이미지 링크 서빙 정책을 변경한다.

firebase storage에 업로드 된 결과물에는 아래처럼 png로 정상적으로 인식이 되고 있다.

따라서 업로드 후 리턴되는 링크의 포맷만 변경하면 될 것으로 보인다.

아까 받았던 url의 형식을 확인해보자.

https://firebasestorage.googleapis.com/v0/b/{bucket 주소}/o/images%2F1678426359858?alt=media&token={엄청 긴 토큰 값}

우선 이 뒤의 토큰 값을 제거하려면, 버킷을 public으로 공개해야 한다.

가설 검증

그러면 GCP에서, public으로 된 버킷에 업로드 한 이미지의 로드 속도를 한번 비교해 봐야 한다.

임의로 버킷을 하나 생성하고, public으로 한 뒤 테스트를 해봤다.

https://storage.googleapis.com/upload-resume-e4ddb.appspot.com/image-test/jk.png

우선 이미지 링크는 S3와 동일하게, png임을 명시하도록 변경되었다.

업로드 속도는 개선이 됐을까?

버킷에 올라간 후 최초 요청 속도는 기존에 비해 2배 정도 속도가 개선됐다. 또한 한 번 호출이 된 이미지는 캐싱이 되기 때문에, 초기 호출 이후에는 기대했던 만큼의 속도가 나온다!

해결

Google cloud platform 수정

GCP에서 해당 버킷을 공개처리하면 된다.

  1. 버킷 맨 오른쪽의 메뉴 버튼을 누르고, 액세스 수정을 선택한다.

  2. 주 구성원 추가를 누르고

  3. allUser를 viewer로 추가한다.

2개의 댓글

comment-user-thumbnail
2024년 4월 25일

감사합니다

답글 달기
comment-user-thumbnail
2024년 10월 30일

진짜 대단하십니다 감사드려요!

답글 달기