캐시컨트롤에 대해
안녕하세요.
이번 글은 http 프로토콜의 cache-control 헤더에 대해 글을 쓰려합니다.
토스 기술 블로그의 글을 참고했습니다.
캐싱이란
캐싱(Caching)은 한 번 가져온 데이터를 가까운 곳에 저장해 두고, 다음번에 다시 먼 곳에서 그것을 가져올 필요 없이 저장해 둔 것을 사용하는 일종의 성능 향상 기법입니다.
사전적으로는 은닉처라는 뜻을 가지고 있습니다. 주변에 데이터를 숨겨 놓는다고 생각하면 잘 지은 것 같네요.
CPU에서도 캐시 메모리(L1, L2, L3)에 자주 사용되는 데이터를 저장해 둬서 CPU가 데이터를 빠르게 가져올 수 있도록 하는데, 이것도 캐싱의 한 예입니다.
HTTP에서의 캐시
HTTP 프로토콜은 클라이언트와 서버 간의 통신에서 매번 새로운 데이터를 요청하고 응답하는 것이 아니라, 이전에 가져온 데이터를 가져와 사용하는 경우가 많습니다. 이는 매번 새로운 데이터를 가져오는 것보다 더 빠른 성능을 제공하기 때문입니다. 또한 서버의 부하를 줄일 수 있습니다. 이를 가능하게 하는 것이 바로 캐싱입니다.
HTTP에서 리소스는 웹 브라우저가 HTTP 요청으로 가져올 수 있는 모든 종류의 파일을 말하며, HTTP, CSS, JS, 이미지, 비디오 파일 등이 리소스에 해당합니다.
HTTP의 Cache-Control 헤더
HTTP의 Cache-Control 헤더는 리소스를 언제까지 캐시 할 것인지를 지정하는 디렉티브를 가지고 있으며, 쉼표로 구분됩니다.
max-age
Cache-Control의 max-age는 초 단위로 지정되며 만료 후 브라우저는 서버에 다른 요청을 전송하여 해당 버전의 리소스를 새로 고쳐야 합니다. 유효기간이 지나기 전이라면 브라우저는 서버에 요청을 보내지 않고 디스크 또는 메모리에서만 캐시를 읽어와 계속 사용합니다. cache가 있으면 그것을 사용합니다.

크롬 브라우저에서의 디스크 캐시 : disk에 저장되는 기법.
크롬 브라우저에서의 메모리 캐시 : ram에서 가져온 것
no-store
no-store는 캐싱을 아예 하지 않겠다는 뜻입니다.
no-cache
max-age = 0과 동일한 뜻입니다. 캐시는 저장하지만 사용 시마다 서버에 재검증을 요청한다는 의미입니다.
재검증 요청 헤더로 If-None-Match와 If-Modified-Since가 있으며, 이는 기존에 받았던 리소스의 응답 헤더에 있는 ETag( 특정 버전의 리소스를 식별하는 식별자. )와 Last-Modified 값을 사용합니다.
- If-None-Match: 캐시된 리소스의 ETag 값과 현재 서버 리소스의 ETag 값이 같은지 확인합니다.
- If-Modified-Since: 캐시된 리소스의 Last-Modified 값 이후에 서버 리소스가 수정되었는지 확인합니다.


만약 재검증의 요청이 서버에 저장된 정보와 다르다면 서버는 200 OK 또는 다른 상태코드들과 함께 새로운 본문을 내려주게 됩니다. 이를 통해 요청 한 번으로 검증과 업데이트를 할 수 있게 됩니다.
public , private
Cache-Control 값으로 public 또는 private을 추가하여 CDN과 같은 중간 서버가 특정 리소스를 캐시 할 수 있는지 여부를 지정할 수 있습니다. public은 모든 사람과 중간 서버, private은 가장 끝의 사용자 브라우저만 캐시를 저장할 수 있습니다.
s-maxage
중간 서버에서만 적용되는 max-age 값을 설정하기 위해 s-maxage 값을 사용할 수 있습니다.
캐시의 생명
중간서버에 저장된 캐시는 사용자가 가져가 다시 캐시를 합니다.
그렇다 보니 CDN 등에 저장된 캐시로 인해 서버의 업데이트 정보가 즉시 반영되지 않을 수 있습니다. 이 경우는 중간 서버의 캐시를 삭제해야 합니다. 이는 CDN Invalidation라고 불립니다. 이렇게 어려운 절차가 있기 때문에 max-age값을 잘 정해야 합니다.
토스의 경우는 Html, js, css 마다 다른 전략을 가지고 있어 보입니다.
예로 html의 경우는 사용자는 no-cache 중간서버에 1년 동안 cache 하고 배포 때마다 invalidation을 진행합니다.
js, css는 url 상에서 임의의 버전 정보를 넣어 사용하기에 max-age를 1년으로 잡고있다고 합니다.
이렇게 되면 업데이트가 없다고 가정하면 캐시기간을 1년씩 가져가기에 성능에 좋은 영향이 갈 수 있습니다.
저의 경우는 깊게 생각해보지 않았지만 토스처럼 트래픽이 많은 회사들은 캐싱 전략도 잘 짜여 있구나라고 배울 수 있는 기회였습니다.
웹 서비스 캐시 똑똑하게 다루기
웹 성능을 위해 꼭 필요한 캐시, 제대로 설정하기 쉽지 않습니다. 토스 프론트엔드 챕터에서 올바르게 캐시를 설정하기 위한 노하우를 공유합니다.
toss.tech
Cache-Control - HTTP | MDN
The Cache-Control HTTP header field holds directives (instructions) — in both requests and responses — that control caching in browsers and shared caches (e.g. Proxies, CDNs).
developer.mozilla.org