웹 캐시(Web-cache)는 웹에서 사용하는 캐시를 뜻한다. 캐시가 뭘까?
캐시란?
데이터나 값을 미리 복사해두어 사용하는 장소를 뜻한다. 어떤 값을 다시 계산하는 시간을 줄이기 위해 캐시를 사용한다. - https://ko.wikipedia.org/wiki/캐시
캐시가 된 리소스는 서버에 해당 리소스를 요청하지 않고 캐싱된 리소스를 사용한다. 이러한 웹 캐시는 주로 서버의 부하를 줄이기 위해 사용하거나 응답시간을 빠르게 하기 위해 사용하게 된다. 캐시의 사용전략이 곧 성능의 향상이나 리소스 낭비를 줄이는 방법이 될 수 있다.
캐시에 관한 설정을 하는 대표적인 헤더이다. Cache-Control
의 사용되는 값들을 살펴보자.
캐시의 유효기간을 설정하는 값이다. max-age=<seconde>
로 사용된다.
CDN과 같은 중간 서버를 두는 경우, 해당 서버의 캐시 유효기간을 설정할 때 사용한다.
캐싱을 해야할 정보가 다른 곳에는 캐싱되지 않고 오직 해당 브라우저에만 캐싱되도록 하려면 private
을 사용해야한다.
반대로 public
을 사용한다면 다른 클라이언트들도 해당 리소스를 캐싱하게 된다.
모든 response를 새로운 response를 받기 위해 사용하는 것이 no-cache
이다. no-cache
방식은 max-age=0
을 설정한 것과 같은 효과를 가진다. no-cache
와 헷갈리는 것이 no-store
다. 이 방식은 아예 캐시를 저장하지 않는 방식이다. no-cache
보다 no-store
를 사용하는 것이 좋다. (아래 설명하겠다.)
해당 리소스의 변경이 없을 때 사용한다. 이 리소스는 항상 캐싱해두고 사용하게 된다. 또한, reload나 브라우저 종료에 의해서도 지워지지 않는다.
revalidation을 진행한다. 재 검증을 통해 해당 리소스가 유효한지 체크하게 된다.
max-age와 같이 캐시의 유효기간을 설정하는 헤더. 만료되는 날짜를 기록한다. 하지만 날짜는 오류가 발생가능성이 크기 때문에 권장은 max-age
로 하는 것이 권장된다.
같은 URL에 다른 식별자를 적용하여 캐싱하고 싶을 때 사용한다. 예를 들면 https://example.com/index.html
과 같은 페이지를 가져올 때, 한글이냐 영문이냐에 대한 정보를 같이 캐싱하고 싶을 수 있다. 이 때 Vary: Accept-Language
로 값을 설정한다면 Accept-Language
에 따라 다른 정보를 캐싱할 수 있게 된다.
Vary: Accept-Language
response가 stale해지면 해당 response를 재사용하지 않는다. response를 revalidation하기 위해 서버에 If-Modified-Since 값을 보내서 확인하게 된다. 서버에서 변경사항이 없다면 304(Not Modified)를 보내게 되고 클라이언트는 response에 대한 정보를 갱신하여 저장하고 다음 캐시 갱신 전까지 이 정보를 사용하게 된다.
response가 stale해지면 캐시가 유효한지 검증하기 위해 revalidation을 진행한다. 이 때 사용하는 것이 ETag와 If-None-Match이다.
ETag는 서버가 임의로 만든 값이다. 이 값은 주로 response body를 해싱하던가 버저닝을 통해 값을 정한다.
response가 stale해지면 ETag의 값을 If-None-Match
의 값을 ETag값으로 설정한 후, 서버로 보내서 validation을 진행하게 된다. 서버에서 현재 값과 비교 후에, 변한 것이 없다면 304(Not Modified)로 reponse가 올 것이고 캐싱정보를 갱신하게 된다.
캐시는 서버의 부하를 줄여주고 리소스 로드도 빠르게 해준다. 하지만 outdate한 정보나 원치 않는 정보의 캐싱이 일어날 수 있기 때문에 캐싱을 잘 사용해주어야 한다.
no-store는 캐싱하지 않는 방법이다. 이렇게 되면 항상 새로운 요청을 보내게 되고 새로운 정보를 항상 요청하게 된다. no-store를 사용하는 이유는 크게 3가지로 구분된다.
하지만 위 경우에도 no-store
보다는 다른 캐싱전략을 사용하는 것이 좋다.
개인적인 resource라면 private
을 이용하는 것이 좋다. 이를 설정하게 되면 해당 정보는 다른 클라이언트에는 캐싱되지 않고 오직 마지막 브라우저의 유저에게만 캐싱된다. 주로 로그인 정보를 캐싱해두는 쿠키를 사용할 때 private
을 사용하면 좋다.
no-cache
를 이용한는 것이 좋다. no-store
를 이용하는 경우 기존에 저장된 캐쉬는 사라지게 할 방법이 없기 때문이다. 그래서 no-cache
를 통해 캐시의 유효성을 검사하고 새로운 캐시로 대체하는 것이 정보의 무결성을 보장하게 된다.
oudated한 정보를 다룰 때, 여러가지 옵션들(max-age=0, must-revalidation…)을 쓰는 것 보다 no-cache
하나로 해결할 수 있다.
변하지 않는 리소스가 있다면 immutable
값을 이용하면 캐싱해두고 reload에 의해 갱신되지 않기 때문에 효율적이게 된다.
중간에 shared cache 서버를 둔다면 더 효율적으로 운영할 수 있다. 다수의 클라언트의 요청이 와도 CDN과 같은 서버에서 서버로 1회 요청을 보내어, 그 response를 다수의 클라이언트의 response로 보낼 수 있게된다. 이 와같은 방식을 request callapse라고 한다.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching/request-collapse.png
기본적으로 휴리스틱 캐싱이 일어나기 때문에 캐싱전략을 명시하는 것이 좋다.
JS, CSS 파일의 이름을 매번 버저닝이나 해싱을 통해 다르게 한다면 URL이 달라질 것이고 이는 해당 URL에 대한 캐싱을 최대한으로 둬도 새로운 버전이 업데이트 된다면 내용 또한 업데이트 시킬 수 있게 된다.
HTTP3에서는 number를 통해 헤더 옵션들을 가볍게 설정할 수 있게 된다.
main-resource는 항상 새로운 response가 필요하기 때문에 no-cache
를 이용하는 것이 좋다.
참고
https://toss.tech/article/smart-web-service-cache
https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching