-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Refactor] 소개페이지 상단 배너 로딩 속도 개선 #428
Conversation
|
먼저 궁금한 점은, 제가 아는 바에 의하면 그런데 사실 현재 상단 배너로 가져오는 이미지 url은 적어도 솝트의 한 기수동안은 변하지 않는 데이터이고, 아마도 ? 갈아껴주어야 하는 상황에서는 서버에서 s3 이미지 주소를 갈아끼워주는 방식인건데, 승희님이 결국 |
추가적으로 제가 아는 바에 의하면 한 번 확인해주시면 감사하겠습니당 |
아 ! 그리고 혹시 궁금한 건데, 제가 소개 페이지 업데이트 작업할 때, 저도 이 부분 최적화를 고려하면서 혹시 이 부분도 고려하시고 수정하신건지 궁금합니당 ! |
하아 열심히 쓴 답장이 날라가서 ㅠㅠㅠ 늦어진 점 죄송합니다 @wuzoo
맞습니다!
직접적으로 영향이 있죠! 서버에서 s3 이미지 주소를 갈아끼워준다고 할지라도 SSG로 불러오는 데이터는 서버에서 데이터를 가져오는게 아니라 저장되어있는 캐시에서 데이터를 가져오기 때문에 반영이 안되는게 앞서 PR에서 언급한 주요 문제였어요! 클라는 계속 캐시에서 데이터를 가져오니까 서버에 변경사항이 생겼을 때 그 변경사항을 캐시에 업데이트해주는 과정이 필요한 상황인거고, 이를 위해 ISR을 도입한 겁니다!
캐시가 되는건 Vercel에서 배포되었기 때문인 것보다 SSG방식으로 데이터패칭을 하기 때문인게 더 주 요인이에요! 그리고 알려주신 cache 비활성화 전략 알아보았는데, 이는 말그대로 특정 데이터 패칭에 캐시 비활성화 기능을 걸어놓는거고, 그럼 저희는 소개 페이지 페칭에 저 옵션을 추가해야 하는건데, SSG는 빌드된 데이터를 캐시에서 가져오는 원리라 강점인 친구인데 SSG 페칭에 캐시 비활성화 옵션을 넣어버리는건 모순이라고 생각해요. 그럴거면 SSG를 안쓰는것과 매한가지가 되는게 아닐까유?!
맞아요! 말씀하신 부분을 next/image 컴포넌트는 자동으로 제공해줍니다! webp, avif로 최적화를 해주고, 만약 이를 지원하지 않는 환경인 경우엔 원본 파일 제공해요. (fallback처리가 된다는 뜻)
헉 이부분은 완전 몰랐어요. 덕분에 알았네요! 감사합니다 요 부분은 어떻게 개선할지 좀더 이것저것 시도해보고 다시 멘션드릴게용 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
늦어서 죄송해요 너무 고생하셨습니다!!
❓왜하필 2분인가요?
사실 소개페이지는 기존에 SSG를 썼던 만큼 잦은 업데이트가 전혀 불필요한 페이지예요. 다만 서버 데이터상의 변경이 생겼을 경우 이게 반영은 되어야 하니까 너무 긴 주기를 주고 싶진 않았고, 하지만 또 사용자가 접속하는 시간동안 서버 데이터가 바뀌는 일이 매우 드문건 사실이잖아요? 따라서 대부분의 경우에 사용자가 참여하는 한 세션 동안 새로이 revalidate 하면서 불필요한 서버 요청을 일으키는 것도 피하고 싶었어요. 그래서 GA로 사용자 체류시간을 봤는데 소개페이지는 평균 체류시간 약 50초, 전체 페이지 평균 체류 시간 약 1분 20초, 한달 내 최대 체류 시간 약 1분 50초 이길래 이보다 긴 2분으로 설정했습니다.
한달 내 최대 체류 시간 약 1분 50초인데 2분으로 설정하는 건 사실상 revalidate를 하지 않는 거 같아요!
이게 매 2분 마다 계속해서 revalidate를 하는 것이 아니라 아무나 페이지 진입 후 2분이 지나게 되면 한 번만 revalidate를 해서 caching을 새로 바꿔준다는 거라서요
따라서 새 이미지를 보기 위해선 누군가는 2분 이상 머물러야 합니다
하지만 저희의 최대 시간은 1분 50초라 다소 어려울 거 같아요~
서버에서 데이터가 변했다 하더라도 아무도 2분 이상 들어가있지 않았기에 기존 cache된 데이터가 보이게 될 거예요!
(참고자료로 넣어주신 youtube 영상도 보면 1s로 설정했지만 빠르게 새로고침하면 1s가 지나지 않아 업데이트가 되지 않고 있는 걸 볼 수 있어요!)
따라서 그냥 1초로 변경하는게 더 나을 거 같단 생각입니다
만약 예를 들어 1분으로 설정한다 했을 때 페이지에 1분 이상 머무르는 유저가 발생되기 전까진 모든 유저들이 이전 데이터값을 보게 될 거예요
1분이 지난 후에 들어온 유저들 부터 새로 업데이트된 데이터를 보게 되는 거죠
그런데 1초로 설정한다면 처음으로 1초 이상 접속할 유저가 페이지 진입 하고 1초 후엔 모두가 새 데이터를 보게 될 테니 바로 갈아끼우는 게 낫지 않나 싶어요! (1분의 공백 제거)
서버 비용 때문에 그런 거라면 on demand를 이용하면 될 거 같아요
물론 이건 서버에서 수정이 필요한 거라 쉽진 않을 수 있지만요ㅜ
아니면 그냥 30초 정도로 늘려도 될 거 같습니다
주절주절
사실 이걸 왜 서버에서 받아와야 하는 걸까 고민이 좀 되는 거 같아요어드민에 들어갈 내용 정리하면서도 느낀 건데
6개월 마다 변경되는 거라 변경 빈도가 높은 편도 아닌데
사실 어드민에서 변경하는 거나 코드 딴에서 변경하는 거나 리소스는 동일하게 발생하거든요
문구 이런 거는 그렇다 쳐도 사진은 규격만 동일하게 한다면 바꾸는 거 1초도 안 걸리니까 그냥 하드코딩으로 박는 게 더 낫지 않나 싶은 생각이 들긴 합니다
현재 서버 비용도 많이 들고 한데 비용도 줄일 수 있고
추가로 서버로 부터 이미지 받아오는 것 보다 미리 빌드된 이미지 갔다 넣는 게 속도 면에서도 더 빠를 거 같아서요,,,,
일단 제 개인적인 의견이었고요 이 부분은 좀 더 의논 해보면 좋을 거 같아요
일단 on demand를 제일 먼저 고려했지만 말씀하신 것처럼 서버측에서 코드 작업을 해줘야 하고 현재 서버에서는 말그대로 s3 이미지 올려서 갖다 박는 느낌이라 서버 코드 단에서 변경사항을 감지하는 코드를 추가하는 것보다 클라에서 작업하는게 더 적합한 환경이라고 생각해서 on demand는 선택지에서 제외했습니다!
혹시 이 내용이 출처를 알 수 있을까요?? revalidate 20초로 하고 build start 해서 통으로 실행시킨 영상이에요 default.movvscode 터미널 보시면 언제 캐시 업데이트하는지 볼 수 있도록 콘솔 찍어놨는데 즉 사용자 접속 타이밍과 revalidate 시간은 무관하다는 의미입니다.
말씀하신 영상도 혹시 1:49 얘기하시는거면, 1초 미만으로 연속해서 계속 리프레시를 하는데 1초를 체류했을 때마다 업데이트 되는게 아니라 계속 1초 미만으로 리프레시 시키는데 마지막 요청 후로 1초 지나고 그 이후 최초로 리프레시했을 때 데이터가 업데이트되는 방식으로, 즉 제가 이해한 방식으로 작동되고 있는 것으로 보여요 혹시 제가 뭔가 잘못 짚고 있는게 있다면 말씀해주세요 ! |
아ㅏㅏㅏㅏㅏ 고렇네요 제가 잘못 알고 있었네요 😓 죄송합니다ㅜ |
아우 아닙니다 !! 이런건 시간 뺏는게 아니지요 !~~ 주용님이 언급해주신 next/image로 인한 화질 저하 개선은 따로 이슈 / 브랜치 파서 별도로 진행할 예정이라 |
Summary
소개페이지의 상단 배너 로딩 속도가 너무 느렸어요
소개페이지의 가장 상단 콘텐츠이고 나름 메인 콘텐츠이기 때문에 개선이 시급한 친구라고 생각했습니다 !
(관련해서 아주 불편하다고 제보도 받았구요)
해결책 고민하는 시간은 길었지만 결론적으로 작업한 코드는 정말 별거 없습니다
Screenshot
🪫 개선 전
🔋 개선 후
LCP 3.5초 줄임으로써 Performance 지수를 약 20점 올릴 수 있었습니다 🤙🏻
Comment
🐽 s3에 업로드되어있는 이미지 사이즈 수정 및 webp로 변환
우선 아시다시피 소개페이지의 상단 배너는 저희가 로컬 이미지를 넣어주는 형태가 아니라 s3에 저장되어있는 이미지를 서버에서 받아와서 remote url을 src로 넣어주는 형태입니다
그런데 이 이미지 상태가 심각했어요
렌더되는 너비는 100vw여서 가장 커봤자 2000px보다 작을텐데
저 불러오는 원본 이미지 너비는 무려 16400px........파일 사이즈는 3.8MB.... 거의 100배에 달하게 큰 이미지를 받고 있더라구요
백엔드 개발자분이 피그마에서 이미지를 추출해갈때 화질 저하를 막기 위해 4배로 뽑아가신게 원인이었어요
이게 가장 치명적인 문제였기에
이미지 다시 리사이징하고 또 최적화를 위해 형식도 webp로 변환해서 백엔드분께 파일 변경을 부탁드렸습니다
이미지 리사이징은 너비
4000px
로 했어요. 2000px로 하니까 기존 배너보다 확실히 화질 저하가 발생하더라구요그래서 기존보다 최대한 화질 차이 안나는 선에서 최소한으로 줄인 크기가 4000px 였습니당
무튼 그렇게 리사이징 + webp 변환해서
3.8MB
->288KB
로 줄일 수 있었습니다여기서 로딩 속도 개선 끝났다~ 싶었는데 별안간 이슈가 발생했어요
🐽 SSG 형식으로 불러오던 소개페이지 데이터를 ISR 형식으로 수정 (revalidate 간격 120초)
그 이슈는 ... 이미지 파일 갈아끼고 나서 데브 모드에서 빠르게 로딩되는거 확인하고 배포서버에도 반영해달라고 요청을 드렸는데
분명 서버에서는 이미지를 교체했는데 그게 저희 배포본에는 반영이 안되는거예요
브라우저 캐시 문제라고 생각해서 온갖 캐시 다 지우고 이 브라우저 저 브라우저에서 다 시도해보았는데 이미지는 절대 업데이트 되지 않았어요
그래서 네트워크 탭으로 SSG로 불러오고 잇는 about.json을 찾아보니
vercel cache에 HIT를 치고있더라고요?
즉, 제가 삽질하고 있던
브라우저 캐시
가 아닌, SSG 사용으로 인한vercel 캐시
에 저장되어있던 친구였어요.장황한 설명 생략하고 결론만 말씀드리면,
Vercel
에 배포된Next
배포본에서SSG
로 불러오는 데이터는 Vercel의 _next 캐시에영구적으로
저장이 되어서,이후 해당 캐시를 항상 사용한다고 하더라고요.
즉 재배포가 되기 전까지는 영구적으로 동일한 캐시데이터를 사용하게 되는거죠. (SSG의 효과가 바로 이 친구 덕분이겠죠?)
그런데 SSG의 강점을 위해 제공하는 이 기능은 딱봐도 한계점이 보이죠.
바로 제가 이번에 겪은 상황처럼 서버 데이터가 변경될 경우 이게 반영이 안된다는 점인데요,
그 한계를 개선하기 위해 next13버전에서 등장한게
ISR
(Incremental Static Regeneration) 이라고 합니다나랑 같은 니즈를 가진 사람의 호소문
Lee Robinson 씨의 ISR 소개
SSG의 장점은 최대한 가져가되, revalidate 주기를 지정해줘서 주기적으로 해당 데이터를 update 시켜줄 수 있는 방식입니다
따라서 이 revalidate 옵션을
2분
으로 설정해줌으로써 SSG -> ISR 방식으로 수정해서배포본(pnpm build -> ppm start)에서 갱신된 서버 데이터 잘 반영되는 것까지 확인했습니다!
궁금하실만한 부분 몇까지 더 첨언하자면
❓왜하필 2분인가요?
❓근데 그럼 2분마다 데이터가 stale하게 된다면, 사용자가 새로 접속할 때마다 새로이 데이터를 불러오는건데 그럼 SSG의 효과가 떨어지는 것 아닌가?
내용이 다소 두서없을 수 있을 것 같아요 🥵🥵🥵...
그리고 ISR에 대해 공유드리고 싶은 부분들이 더더 많이 남아있어서 아티클 완성되면 여기에 추가해놓겠습니다!!
🐽 상단 배너 element를 div 태그 -> next/image 컴포넌트로 수정
마지막 최적화 단계인데요,
이미지 리사이징을 했지만 화질저하 때문에 여전히 큰 이미지를 가져오고 있기 때문에
next/image
컴포넌트를 사용해서 한번 더 리사이징 및 최적화를 해주었어요.기존에는 그냥 div 태그에 background-image로 삽입하는 형식으로 구현되어있더라구요?
그런데 상단배너는 이미지 위에 별도의 콘텐츠가 있는 것도 아니라서 기존의 background 방식을 유지할 필요가 없었어요
따라서 next/image 컴포넌트로 바꿔줌으로써 화면에 fit한 사이즈로 리사이징해주며 한단계 더 최적화해주었습니다
이렇게 해서 최종적으로
3.8MB
로 들어오던 file size를5.2kB
까지 줄일 수 있게 되었어요 !+) 노드 버전으로 인한 CI 에러 때문에 yml파일 수정해줬습니다