지난주 모던 리액트 딥다이브 스터디에서 Next.13에서 도입된 서버 컴포넌트를 소개하였는데, 서버의 부담을 줄여줄 수 있지만 비용이 늘어날 수 있어 서버와 클라이언트 간 작업을 균형 있게 분배 해야 한다는 결론이 나왔습니다. 이에 SSR과 서버 컴포넌트를 효율적으로 도입할 수 있는 방안으로 중간 서버인 CDN의 캐싱을 적절히 활용해 볼 수 있겠다고 생각하였고, 캐시에 대한 전반적인 내용과 CDN에 대해 정리해 보았습니다.
캐시
캐시란 데이터나 값을 미리 복사해 놓은 임시 저장소를 뜻합니다. 캐시는 원본 데이터에 접근하는 시간이 오래 걸리거나 값을 다시 계산하는 시간을 절약하고 싶은 경우에 사용할 수 있습니다. 이렇게 캐시에 데이터를 미리 복사해두면 계산이나 접근 시간 없이 빠른 속도로 필요한 데이터에 접근할 수 있습니다. 즉, 속도는 높이고 비용은 절감할 수 있습니다.
캐시는 컴퓨터 전반에 걸쳐 사용됩니다. 그 가운데 이번 포스팅에서는 브라우저 캐시와 공유된 캐시에 대해 알아보겠습니다. 브라우저 캐시는 클라이언트에 저장되는 캐시로, 각 유저를 위해 개인화된 콘텐츠를 저장하고 재사용합니다. 로컬 캐시, private 캐시, 또는 HTTP 캐시라고도 불립니다. 공유된 캐시는 클라이언트와 origin 서버 사이에 존재하는 캐시로, Proxy나 CDN을 말합니다. 하나의 응답을 저장하고, 여러 사용자에게 재사용하는 역할을 합니다. 따라서 공유된 캐시에는 개인화된 콘텐츠를 저장하지 말아야 합니다.
브라우저 캐시
브라우저는 서버에 요청을 보내기 전 먼저 브라우저 캐시에 접근해 캐싱된 데이터가 있는지 확인하고 있으면 해당 데이터를 사용합니다. 이때 효율적인 업데이트를 위해 max-age, ETag, 그리고 cache-busting 패턴을 사용합니다. 하나씩 천천히 어떤 문제를 해결하는지 알아보겠습니다.
max-age
브라우저는 브라우저 캐시에 저장된 데이터가 있는 경우 서버에 요청을 보내지 않고 캐싱된 데이터를 사용합니다. 이때 서버에 있는 데이터가 업데이트 된다면 어떻게 될까요? 사용자가 업데이트된 내용을 볼 수 있도록 브라우저에서 일정 시간 동안만 캐싱을 하고 이후에는 새로운 요청을 통해 브라우저 화면을 업데이트해야 할 것입니다. 따라서 서버는 리소스 응답 시 브라우저가 캐시 데이터를 언제까지 사용해야 할지 판단할 수 있도록 해당 리소스를 캐싱할 수 있는 시간을 명시해서 응답합니다. 이 내용은 HTTP Cache-Control 헤더에 max-age 값으로 명시합니다. max-age는 리소스를 캐싱 가능한 최대 시간을 초로 나타냅니다. 예를 들어, max-age=60은 60초 동안 캐시되어 재활용될 수 있다는 뜻입니다.
ETag
max-age를 활용하면 브라우저가 업데이트 된 서버 데이터를 일정 시간 후에 새롭게 받아오도록 할 수 있습니다. 하지만 만약 max-age가 지나 캐시가 만료되었지만, 리소스는 변함이 없다면 어떨까요? 리소스가 변경되지 않았음에도 서버가 계속해서 이에 대해 응답하고 클라이언트가 이를 다운로드하는 일이 주기적으로 반복될 것입니다. 하지만 변경되지 않은 리소스를 서버에서 다운로드하는 작업은 비효율적입니다. 이미 캐시에 동일한 정보가 있는데 굳이 요청하여 다운로드할 필요가 없기 때문입니다. 이때 ETag를 활용하여 문제를 해결할 수 있습니다.
ETag는 특정 버전의 리소스를 구분하는 식별자로, 특정 URL의 리소스가 변경될 경우, 새로운 ETag가 생성됩니다. ETag는 보통 콘텐츠의 해시, 마지막으로 수정된 시간의 해시, 또는 개정번호 등을 사용하여 생성합니다. 예를 들어, MDN은 콘텐츠의 16진수 해시를 사용합니다.
ETag는 다음과 같은 순서로 사용됩니다.
1. 사용자가 URL을 재방문했을 때, 보유한 ETag가 오래되어 사용될 수 없다고 판단되면, 클라이언트는 If-None-Match 헤더 필드에 ETag를 전송합니다.
2. 서버는 클라이언트의 ETag를 현재 버전 리소스의 ETag와 비교하고, 변경 사항이 없는 경우 304 Not Modified 상태를 반환하여 캐시된 버전이 유효함을 알립니다.
따라서 ETag를 사용하면 변경되지 않은 리소스를 서버에서 다운로드하지 않아 효율적인 리소스 업데이트 검사가 가능합니다.
304 Not Modified
- 요청된 리소스를 재전송할 필요가 없음을 나타내는 클라이언트 리디렉션 응답 코드이다.
- 암묵적으로 캐시된 자원으로 리디렉션한다.
Cache-Busting
max-age와 ETag를 사용하면 일정 시간마다 변경된 경우에만 리소스를 업데이트할 수 있어 효율적인 것을 알아보았습니다. 그렇다면 리소스의 만료 기한인 max-age를 길게 준 상태에서 서버 데이터가 업데이트되면 어떻게 할 수 있을까요? 이는 리소스 URL을 변경하는 방식으로 해결할 수 있습니다. 주로 파일의 버전 번호나 날짜, 해시값 등을 파일 이름에 포함하는 방식으로 수행하며, 브라우저는 리소스 URL이 변경되면 새로운 데이터로 인식하기 때문에 새롭게 다운로드를 합니다.
mdn에서도 cache-busting 패턴을 아래와 같이 소개합니다.
A modern best practice for static resources is to include version/hashes in their URLs, while never modifying the resources — but instead, when necessary, updating the resources with newer versions that have new version-numbers/hashes, so that their URLs are different. That's called the cache-busting pattern.
정적 리소스를 관리하는 최선의 방법은 리소스 자체를 변경하지 않고, 리소스의 URL에 버전이나 해시값을 포함하는 것입니다. 그 대신에, 필요한 경우 새로운 버전 번호와 해시값을 가진 새로운 버전의 리소스로 업데이트하여 다른 URL을 가지도록 합니다. 이를 cache-busting 패턴이라고 합니다.
보통 정적 파일(JavaScript, CSS)은 max-age 값은 길게 두고, 파일의 버전 번호를 명시해 수정 시마다 파일을 업데이트합니다.
또한, cache-busting 패턴과 함께 max-age를 길게 잡는 경우 immutable 헤더를 추가하면 불필요한 재검증을 막을 수도 있습니다. immutable은 캐시가 유효한 동안 콘텐츠가 변경되지 않을 것임을 나타내어 서버에 불필요한 조건부 요청을 하지 않도록 합니다.
구글 첫 페이지에서 받아오는 리소스 가운데에도 이러한 패턴을 적용한 요청을 볼 수 있었습니다.
CDN(Content Delivery Network)
CDN은 클라이언트와 웹 사이트 서버 사이 서버를 두어 지리적 제약 없이 빠르고 안전하게 콘텐츠를 전송할 수 있는 전송 기술입니다. 사용자에게 지리적으로 가까운 CDN 서버에 콘텐츠를 저장하여 빠르게 콘텐츠를 전달할 수 있습니다.
CDN의 이점
1. 캐싱 및 최적화를 통해 origin 서버에 실제로 요청하는 데이터 양을 줄여 호스팅 비용 절감 및 페이지 로드 시간 단축
2. CDN은 로드밸런싱을 사용해 요청을 여러 서버에 분산시킴으로써 트래픽 급증에 효과적으로 대응한다. 이를 통해 DDoS 공격, MITM 공격으로부터 시스템을 보호하고, 콘텐츠 가용성을 높인다.
콘텐츠를 캐싱하여 사용자와 가까운 서버에서 리소스를 반환하므로 origin 서버에 도달하는 요청이 줄고, 페이지를 빠르게 로드할 수 있음을 알 수 있습니다. 이뿐만 아니라, 대량의 요청이나 패킷을 보내 시스템을 마비시키는 DDoS(Distributed Denial of Service) 공격이나 서버와 사용자 간의 통신을 가로채거나 변경하는 MITM(Man-In-The-Middle)와 같은 공격을 받는 경우에도 origin 서버에 직접적으로 도달하는 것을 막거나 로드를 분산하여 효율적으로 대응합니다. 이를 통해 필요할 때 리소스를 반환할 수 있도록 시스템을 유지할 수 있는 능력인 가용성을 높입니다.
언제 사용할까요?
그렇다면 콘텐츠를 빠르고 안전하게 전달할 수 있는 중간 서버로 CDN을 항상 사용하면 될까요? 앞서 언급한 장점을 생각해 보면 많은 미디어를 포함한 웹사이트, 지리적으로 분산된 사용자 그룹, 빠르게 전달해야 할 중요한 콘텐츠가 있는 경우 활용하면 좋을 것입니다. 구체적인 예로는 동영상 스트리밍, 온라인 게임, 대용량 파일 전송, 해상도가 높은 이미지를 사용하는 쇼핑몰이 있습니다.
하지만 하지만 특정 국가나 지역을 타겟으로 한다면 오히려 불필요한 연결 지점이 늘어나 웹 사이트의 성능 저하를 불러올 수 있으므로 유의해야 합니다.
CDN의 작동 방식
CDN은 각 지역에 캐시 서버(PoP, Points of Presence)를 분산 배치하거나 CDN 에지 서버 그룹을 설정하는 방식으로 작동합니다. 지리적으로 분산된 CDN은 캐싱, 동적 가속, 엣지 로직 계산의 원리를 기반으로 작동합니다.
캐싱
- 네트워크의 여러 서버에서 정적 웹 사이트 콘텐츠를 저장하는 과정으로 동작 순서는 아래와 같습니다.
- 지리적으로 멀리 있는 사용자가 사이트에서 처음 요청
- 요청이 웹 어플리케이션 서버 또는 origin/host 서버에 도달한다. origin 서버는 사용자에게 응답을 보내고, 해당 사용자와 지리적으로 가장 가까운 CDN POP에 응답의 복사본을 보낸다.
- CDN POP 서버는 복사본을 캐싱된 파일로 저장
- 해당 위치에 있는 사용자가 동일한 요청을 하면 origin 서버가 아닌 캐싱 서버가 응답을 보낸다.
동적 가속
- 동적 웹 콘텐츠 요청에 대한 서버 응답 시간을 단축하는 과정입니다.
- CDN 서버는 모든 동적 콘텐츠 요청이 있을 때마다 origin 서버와 다시 연결해야 하지만, origin 서버와의 연결을 최적화하여 이 과정을 가속화합니다.
활용 사례
- 온라인 동영상 스트리밍 서비스를 제공하는 Netflix는 콘텐츠를 안정적이고 빠르게 세계 각지로 전달하기 위해 자체 구축한 CDN을 사용합니다.
- 숙박 공유 서비스인 Airbnb는 CDN을 활용해 전 세계 고객이 언제 어디서나 숙박 시설을 예약할 수 있는 서비스 환경 구축합니다.
- NC 소프트나 카카오게임즈는 CDN을 활용해 북미나 유럽처럼 지리적으로 먼 지역의 사용자에게 안정적이고 빠른 게임 플레이 환경을 제공합니다.
정리
캐시를 활용하면 계산이나 접근 시간을 단축하여 더 빠른 속도로 필요한 데이터에 접근할 수 있습니다. 브라우저 캐시는 클라이언트에 각 사용자를 위한 개인화된 콘텐츠를 저장하고, CDN과 같은 공유된 캐시는 클라이언트와 origin 서버 사이에 존재하는 캐시로, 하나의 응답을 저장하고 여러 사용자들에게 재사용합니다. CDN을 사용하면 캐싱과 최적화를 통해 지리적으로 먼 사용자에게도 안전하고 빠르게 데이터를 전달할 수 있습니다. 이러한 캐시의 만료 시간이나 동작 방식은 Cache-Control HTTP 헤더를 사용하여 지정할 수 있으며, 이를 통해 데이터를 효율적으로 가져올 수 있습니다.
REF
CDN
CDN(Content Delivery Network)이란? - IBM
콘텐츠 전송 네트워크(CDN)란 무엇인가요? - AWS
캐시
그 외