abonglog logoabonglog

브라우저의 캐시 사용법 및 NextJS 에서 캐시를 사용하는 방법 의 썸네일

브라우저의 캐시 사용법 및 NextJS 에서 캐시를 사용하는 방법

웹 브라우저 지식

프로필 이미지
yonghyeun

캐시 (cache)

캐시란 데이터들을 미리 복사해놓은 임시 저장소를 가리킨다. 어떤 데이터에 대한 접근 시간보다 캐시에 접근하는 것이 더욱 빠를 때 사용된다. [1]

웹 사이트와 애플리케이션의 성능은 이전에 사용했던 리소스를 재사용함으로서 현저히 향상 될 수 있다. 웹 캐시를 통해 네트워크 트래픽을 줄여 리소스를 보여주는데 필요한 시간을 줄일 수 있을 뿐더러 서버의 부담을 줄여주기 때문이다.

이번 게시글에선 브라우저가 사용하는 메모리 캐시와 디스크 캐시에 대해 알아보고 브라우저가 캐시를 어떻게 사용하는지 알아보고자 한다.

브라우저 캐시의 종류

브라우저 캐시는 클라이언트 측에 보관되는지, 서버와 클라이언트 사이에 존재하는 중개 서버에 존재하는지에 따라 나눌 수 있다.

  • 클라이언트측 보관 캐시
    • 메모리 캐시
    • 디스크 캐시
  • 서버 공용 캐시
    • CDN

메모리 캐시

메모리 캐시란 브라우저가 실행중인 동안 RAM (Random Access Memory) 에 데이터를 저장하는 임시 저장소다.

CPU 와 가까워 접근 속도가 매우 빠르지만 용량이 제한적이기에 휘발성이 강해 시스템이 종료되면 데이터가 삭제 된다.

주로 웹 페이지를 로드 할 때 사용되는 작은 크기의 데이터들을 메모리 캐시에 저장해둔 후, 다시 필요할 때 서버에서 다시 다운로드 하지 않고 메모리에서 빠르게 로드 한다.

CSS , JS 와 같은 파일이나 작은 이미지 파일 혹은 API 데이터등이 메모리 캐시에 저장된다.

페이지 초기 로딩페이지 초기 로딩

페이지에 처음 진입 했을 때는 캐시에 아무런 데이터가 존재하지 않기에 모든 데이터를 직접 서버에 요청한다.

페이지 초기 진입 후 캐시를 이용하는 예시페이지 초기 진입 후 캐시를 이용하는 예시

하지만 브라우저를 닫지 않은 채로 화면을 새로고침하여 재요청을 보낼 시엔 html 문서를 제외하고선 모두 memory cache 에서 데이터를 불러오는 모습을 볼 수 있다.

디스크 캐시

디스크 캐시란 하드 디스크에 데이터를 저장하는 캐시로 메모리 캐시에 비해 속도가 느리지만 용량이 크고 브라우저를 닫아도 데이터가 유지된다.

디스크 캐시엔 대용량의 이미지 파일이나 비디오 파일, 폰트 파일, 대용량 JS 등이 저장된다.

브라우저는 메모리캐시와 디스크 캐시에 데이터를 어떻게 나눠 담을까?

브라우저의 캐시는 서버에서 제공하는 캐시 컨트롤 관련 헤더를 이용해 브라우저 내부의 알고리즘을 통해 데이터를 나눠 저장한다.

예를 들어 max-age 가 짧으면 메모리 캐시에 넣거나, 용량이 크면 디스크 캐시에 넣는등 처럼 말이다.

우리가 알아야 할 것은 어떻게 캐시를 컨트롤 하느냐이기에 캐시를 컨트롤 하는 방법들에 대해 알아본다.

Cache-Control 헤더

캐시 컨트롤 헤더는 요청하는 클라이언트단과 응답하는 서버단 양측 모두에게 캐싱 메커니즘을 위한 디렉티브를 지정하는데 사용된다. [2]

no-cache

no-cache 헤더는 캐시된 데이터를 사용하기 전, 서버에 유효성 검사를 요청하도록 한다.

캐시된 데이터 사용 전 클라이언트는 서버 측에 변경 유무를 확인하기 위해 캐시를 식별 할 수 있는 ETag 또는 Last-Modified 헤더와 함께 조건부 요청을 수행한다.

이후 서버에선 데이터가 변경되지 않아 캐시를 사용해도 된다면 304 Not Modified 응답을 보내거나, 변경된 경우엔 200 ok 헤더와 함께 새로운 데이터를 전송한다.

no-store

캐시되길 원치 않는 민감한 데이터를 이용 할 때 사용한다. 해당 캐시 컨트롤 헤더와 함께 전송된 데이터는 캐싱되지 않는다.

public

public 속성은 브라우저 캐시에 해당하기 보다, 클라이언트와 서버 사이에 있는 중개 서버들에 데이터를 저장 할지 말지를 결정한다.

public 으로 되어 있는 데이터는 프록시 서버 (캐싱 서버) 에 캐싱되어 프록시 서버를 지나는 같은 요청들에 대해 캐싱된 데이터를 전송한다.

private

pirvate 는 해당 응답값이 특정 사용자만을 위한 데이터임을 나타내며 공유되는 프록시 서버에 데이터를 캐싱하지 않도록 한다. (사설 캐싱 서버에는 캐싱 될 수 있다.)

must-revalidate

캐시된 데이터를 사용하기 전 항상 서버에 유효성 검사를 요청하는 헤더로 주로 no-cache 속성과 함께 사용된다.

캐시 유효성 검사

캐시는 이론적으론 영원히 저장 될수 있지만 캐시는 유한한 저장공간을 가지이게 주기적으로 스토리지에서 제거되며 이런 과정을 캐시 축출(cache eviction) 이라 한다. 혹은 캐싱된 데이터가 변경되어 원본 데이터와 다를 수도 있다.

이렇게 캐싱된 데이터가 유효한지 검사하는 과정을 유효성 검사라고 한다.

캐시의 유효성 검증은 시간을 통한 검증과 태그를 통한 검증이 존재한다.

시간을 통한 검증

Last-Modified/If-Modified-SInce

서버는 데이터를 전송 할 때 해당 리소스가 마지막으로 수정된 시간인 Last-Modified 헤더와 함께 전송한다.

브라우저는 추후 캐시된 리소스를 사용 할 때 If-Modified-Since 헤더를 통해 서버에게 조건부 요청을 보내게 되고 서버측은 리소스의 Last-Modified 값과 요청된 If-Modified-Since 값을 비교하여 캐싱된 데이터가 사용 가능하다면 304 Not Modified , 새로 교체해야 한다면 200 Ok 헤더와 함께 새로운 리소스를 보낸다.

Expires/Cache-Control: max-age

서버는 데이터를 전송 할 때 해당 데이터가 유효한 기간을 Expires 헤더 혹은 Cache-Control : max-age 를 이용해 전송한다.

이후 브라우저 측에서 캐싱된 데이터를 사용하기 전 헤더를 확인하여 캐싱된 데이터가 유효한지 확인하고, 만약 유효하지 않다면 서버측으로 다시 요청을 보내게 된다.

태그를 통한 검증

ETag/If-None-Match

서버측에선 리소스를 식별 할 수 있는 고유한 식별자인 ETag 와 함께 데이터를 전송한다.

이후 브라우저측에서 캐시된 데이터를 사용하기 전 If-None-Match 헤더에 사용하고자 하는 리소스의 ETag 를 담아 조건부 요청을 보내게 되고

서버측에선 검증 결과에 따라 304 , 200 응답을 보내게 된다.

Vercel 은 어떤식으로 캐시를 사용하는가 ?

Vercel 은 배포된 버전마다 X-Vercel-ID 를 정의한다.

이후 정적 자산들(css, js , image)등을 모두 immutable 한 데이터로 정의한다

이후 데이터가 새롭게 빌드되어 배포되면 새로운 X Vercel-ID 를 생성하고 이전 X-Vercel-ID 들을 가지고 있는 캐싱된 데이터들을 무효화 한다.

must-revalidate한 문서의 Early Hints headersmust-revalidate한 문서의 Early Hints headers

이후 매번 새롭게 받아야 하는 html 문서의 경우 캐싱된 데이터 사용 가능 여부와 함께 리소스를 받아온 후 해당 응답 문서에 있는 X-Vercel-ID 값을 이용해 메모리에 저장되어 있는 데이터들이 유효한지 확인한다.

이미지에 있는 Ealry Hints Headers 는 리소스가 모두 준비 되기전 필요한 리소드들의 링크들을 담은 헤더라고 한다. [3]

html 문서에 적힌 X-Vercel-ID와 같은 값을 가진 정적 파일들html 문서에 적힌 X-Vercel-ID와 같은 값을 가진 정적 파일들

이후 해당 값이 모두 사용 가능 하다면 캐싱된 데이터를 그대로 사용하고 있는 모습을 볼 수 있다.

출처

  1. 캐시 - 위키백과, 우리 모두의 백과사전
  2. HTTP 캐싱 - HTTP | MDN