어느덧 항해의 마지막 <성능 최적화> 챕터가 시작됐다.
빠르다면 빠르고 느리다면 느리게 지나온 것 같다.
빠르다면 빠르고 느리다면 느린 건 그래서 빠른 걸까 느린 걸까?
최적화는 크게 두 가지로 나눌 수 있다.
인프라 수준의 최적화와 코드 수준의 최적화다.
이번 챕터에서는 인프라 수준의 최적화에 대해 다룬다.
인프라 수준의 최적화란 무엇일까?
인프라 수준의 최적화에서의 핵심 지표는 TTFB(Time To First Byte)다.
TTFB란 클라이언트가 서버에 요청을 보내고 서버로부터 첫 번째 바이트 응답을 받기까지 걸리는 시간을 의미한다.
TTFB를 줄이기 위해서는 캐시 적용, CDN 등의 인프라 레벨의 최적화가 필요하다.
과제는 배포한 Next.js 프로젝트의 CDN 도입 전과 후의 성능 개선 보고서를 작성하는 것이다.
과제의 요구 사항은 위와 같다.
Next.js 프로젝트를 main 브랜치에 push하면 GitHub Actions에서 빌드를 하고 빌드된 산출물을 AWS S3로 업로드한다.
AWS Cloud Front는 CDN 서비스다.
이를 통해 인프라 수준의 성능 최적화를 한다.
이 과정에서 IAM을 통해 AWS 접근을 통제하고 관리한다.
GitHub Actions는 CI/CD 도구다.
GitHub 레파지토리 내에서 코드의 빌드, 테스트, 배포 등 여러 작업을 자동화하기 위해 사용한다.
GitHub Actions는 코드 푸쉬, 풀 리퀘스트, 이슈 생성 등 다양한 GitHub 이벤트에 반응하여 워크 플로우가 실행된다.
레파지토리 내 .github/workflows
폴더에서 YAML 파일로 워크 플로우를 정의한다.
예전에 CI/CD라고 하면 Jenkins만 떠올렸는데, 요즘에는 GitHub Actions를 많이 사용하는 듯하다.
Jenkins와의 차이점은 Jenkins는 오픈소스 CI/CD 도구로, 사용자가 직접 서버에 설치하고 관리해야 한다.
오랜 시간 동안 사용되어 온 만큼 다양한 커뮤니티 지원이 되고, 많은 플러그인을 통해 다양한 환경에 맞춰 확장할 수 있지만 그만큼 러닝커브가 높다.
하지만 GitHub Actions는 GitHub에서 제공하여 별도의 설치가 필요없다.
또한 YAML 파일 하나로 워크플로우를 정의하고 GitHub 이벤트에 기반하여 트리거된다.
GitHub 이벤트가 발생하면 레파지토리 내 .github/workflows
폴더에 있는 모든 YAML 파일을 스캔한다.
각 YAML 파일에 정의된 on
키워드를 확인하여 이벤트에 대한 워크 플로우가 트리거되어 실행된다.
워크플로우 파일에서 빌드된 파일을 AWS에 저장하기 위해 IAM 계정 정보를 입력하여 접근 권한을 얻게 된다.
하지만 이런 정보는 보안상 공개되면 안되는 정보기 때문에 Repository secrets에 저장한다.
Repository secrets에 저장하면 Github 내부에서 암호화되어 저장된다.
워크플로우 파일에서 ${{ secrets.AWS_ACCESS_KEY_ID }}
형식으로 참조할 수 있으며, AWS_ACCESS_KEY_ID는 저장 시에 설정할 수 있는 이름이다.
환경 변수는 워크플로우 실행에 필요한 설정값을 정의할 때 사용한다.
env:
NODE_ENV: production
API_URL: https://api.example.com
워크플로우 파일 안에서 env
키를 사용하여 정의할 수 있고 $NODE_ENV
, ${{ env.API_URL }}
형태로 참조할 수 있다.
이번 과제에서 사용하진 않았지만 민감한 정보가 아니고 워크플로우 파일에서 전역적으로 쓴다면 활용할 수 있다.
S3는 서버라기 보단 스토리지다.
여지껏 jsp + Spring으로 만들어진 프로젝트를 Docker에 배포한 적만 있어서 이 개념이 헷갈렸다.
서버라 함은 OS 위에 Java면 JVM, JavaScript라면 Node.js를 띄운 다음에 코드를 실행시키는 이미지다.
빌드된 파일을 S3에 저장하고 제공된 URL로 접근 시에 페이지를 띄워줘서 서버인 줄 알았다.
S3는 빌드가 완료된 HTML, CSS, JavaScript 파일을 포함한 정적 파일을 갖고 있다가 전달하는 것뿐인데 어떻게 동작할 수 있을까?
빌드된 파일을 S3에 저장하고 제공된 URL로 접근 시에 페이지를 띄워주긴 하지만 그 파일들은 브라우저에서 실행된다.
따라서 S3가 정적 파일을 저장하고 있다가 제공만 해도 브라우저에서 화면을 확인할 수 있다.
과제에서는 create-next-app
으로 만든 프로젝트를 빌드하고 배포해서 괜찮았지만 Next.js 프로젝트를 S3에 배포하는 것은 사실 위험하다.
만약에 png
파일을 Image
컴포넌트를 사용하여 보여준다면 오류가 발생한다.
Next.js의 Image 컴포넌트는 서버 측에서 이미지 최적화를 하기 때문이다.
Image 컴포넌트는 요청이 들어오면 해당 이미지를 변환하고 최적화 하는 과정을 거치는데, 브라우저가 아닌 Node.js나 Vercel과 같은 서버 환경에서 이뤄진다.
즉 동적 서버 환경에서 이미지 최적화 API를 활용하기 때문에 정적 스토리지인 S3에 빌드 결과물을 올리면 오류가 발생한다.
CloudFront는 AWS에서 제공하는 CDN 서비스다.
그럼 CDN 서비스란 무엇일까?
CDN은 Content Delivery Network의 약자로, 쉽게 말해 사용자와 가까운 곳에 파일을 저장하는 저장소이다.
S3 저장소가 사용자와 물리적인 거리가 멀어 파일을 받을 때까지 시간이 오래 걸리는 문제를 사용자와 가까운 엣지 로케이션이라는 곳에 캐싱하여 시간을 단축한다.
사용자가 요청을 하면 CloudFront는 가장 가까운 엣지 로케이션에서 캐싱된 데이터를 제공한다.
또한 HTTP 압축, 불필요한 헤더 제거 등 캐싱 정책에 따라 최적화된 컨텐츠를 전달한다.
CDN을 사용하면 얼마나 빨라질까?
S3의 엔드포인트와 CloudFront의 배포 도메인 주소를 비교해보자.
비교를 위해 https://www.webpagetest.org/ 사이트를 이용했다.
Chapt GPT한테 성능 비교 시각화하고 싶은데 알려달라니 알려줬다. ㅋ
먼저 S3에 직접 접근했을 때의 지표이다.
첫 번째로 나오는 TTFB는 위에서 언급한 핵심 지표다.
그 다음으로 차례대로 설명하면
Cloud Front를 사용하면 얼마나 좋아질까?
모든 수치가 1초를 넘지 않고 확연히 좋아진 걸 알 수 있다.
Page Weight는 약 200kb 줄어들었다.
두 수치를 비교하면 아래와 같다.
성능 지표 | CloudFront (CDN 적용) | S3 (직접 접근) |
---|---|---|
TTFB | 0.175 s | 3.37 s |
Start Render | 약 0.5 s | 약 3.70 s |
FCP | 약 0.48 s | 약 3.71 s |
Speed Index | 약 0.51 s | 약 3.81 s |
LCP | 약 0.48 s | 약 3.95 s |
Page Weight | 194 KB | 483 KB |
캐시 무효화는 CDN에 저장된 캐시된 컨텐츠가 최신 상태가 아닐 때 이를 삭제하거나 갱신하는 과정을 의미한다.
캐시 무효화가 필요한 이유는 웹 애플리케이션의 콘텐츠가 변경되었을 때 사용자에게 최신 데이터를 제공하여 모든 사용자가 동일한 최신 컨텐츠를 받을 수 있게 하기 위해서다.
또한 잘못된 파일이 발견된 경우에 해당 캐시를 제거함으로써 문제를 해결할 수 있다.
이번주 과제는 적혀있는 가이드대로 따라하기만 하면 돼서 비교적 쉬웠다.
하지만 개념이 두루뭉술해서 팀 스터디 시간에 과제 내용에 대해서 얘기를 했다.
개인적으로 공부한 내용을 서술하고 확인받고 그래도 안 잡힌 개념을 다른 팀원분께서 명확하게 설명해주셨다.
두루뭉술했던 부분이 S3는 서버가 아니라 스토리지인데 어떻게 동작할까라는 물음이었는데 시원하게 해결됐다.
요즘 나만의 루틴을 찾으려 노력중인데, 잠이 너무 많다.
줄일 필요가 있다.
사실 잠을 많이 자고 일어나 있는 시간을 알차게 쓰면 베스트지만.. ㅎㅎ
<스시 장인: 지로의 꿈>이라는 다큐멘터리 영화를 봤다.
지난 멘토링에서 추천받은? 영화인데 대충 내용은 스시 하나로 미슐랭 3스타를 받은 스시 장인 할아버지의 일에 대한 이야기다.
어떤 직업을 가질지 결정을 내렸다면 그 일에 몰두해야 합니다.
자신이 하는 일을 좋아하고 그 일에 반해야 합니다.
이게 안돼 저게 안돼 하면 평생을 한들 제대로 되지 않습니다.
기술을 익히겠다고 생각하면 평생 노력하며 기술을 연마해야 합니다.
그게 성공의 비결이죠.
또한 길이길이 남들로 부터 존경받는 비결이라 하겠습니다.
처음 도입부에서 위와 같은 말을 한다.
뭐 저 말에 감명을 받아서 '무조건 저렇게 해야한다!'는 아니지만 뭔가 좋아해서 하는 것보단 좋아해야 해서 하는 것도 중요하구나?라는 느낌을 받았다.
같은 팀원분 중에 개발과 관련된 이야기를 하면 "오~ 흥미로운 이야기인데요?" 혹은 "오~ 너무 재밌는 이야기인데요?"라고 하시는 분이 계신다.
그 분이 전에 좋아한다고 하다보면 어느새 진짜로 좋아지게 된다라고 얘기했는데 오버랩됐다.
가끔 웨이트를 좋아하는 사람(이해되지 않지만) 가운데 특히 하체 운동을 더 좋아하는 사람(더 이해되지 않는다)을 보며 변태가 아닐까 생각했다.
사실 그 사람들도 과정을 즐기기 위해 의식적으로 재밌다고 하는 걸까?
음... 아니다. 하체 운동을 좋아하는 사람은 변태다.
아무튼 흥미를 쫓는 것도 좋지만 의식적으로 흥미롭게 보는 것도 중요한건가 싶다~
잘 보고 갑니다~