스터디 팀원에게 추천받은 자료 공부 후 정리
서론
- HTTP 캐시(웹 캐시)는 웹 성능을 최대한으로 높일 때 사용된다.
웹 캐시를 잘못 관리하면?
- 원하는 시점에 캐시가 안 사라지거나 (새로 요청을 받아와야 하는데)
- 필요 이상으로 HTTP 요청을 하게 되는 비용 발생
캐시의 생명 주기
- HTTP에서의 리소스(Resource)
- 웹 브라우저가 HTTP 요청으로 가져오는 모든 파일
- 예: HTML, CSS, JS, 이미지, 비디오 파일
- 웹 브라우저가 새로운(지금까지 요청한 적 없는) 리소스를 받아오려고 할 때, 서버와 브라우저는 '완전한'(캐시가 관여되지 않는) HTTP 요청 및 응답을 주고 받는다.
- 이후에는 HTTP 응답에 포함된 캐시 관련 헤더(Cache-Control)로 요청/응답의 데이터 조절
max-age: 캐시의 유효 기간
- 해당 리소스의 캐시가 유효한 시간
- Cache-Control 헤더(key)의 값(value)으로 지정됨
- 형태:
max-age=<초>
max-age가 지나기 전
- 이전에 받아온 리소스의 max-age가 지나지 않았다면
- 브라우저가 서버에 요청을 보내지 않고 디스크나 메모리에 있는 '캐시'를 사용
- 가운데 있는
(from memory cache)
를 통해 메모리 캐시에서 불러왔다는 걸 알 수 있다.
cache-control: max-age=31536000
- 이 리소스의 캐시의 유효 기간은 1년(31536000초)이라는 뜻
- 캐시가 이렇게 한번 브라우저에 저장되면 max-age 기간으로 만료될 때까지 브라우저에 계속 남아 있게 됨
- 이는 CDN Invalidation을 포함하여 서버에서 어떤 작업을 해도 브라우저에 있는 캐시를 지우기는 어려움
Cache-Control 헤더의 max-age 대신 Expires 헤더로 캐시의 만료 시간을 초가 아닌 구체적인 시간으로 설정 가능
max-age가 지나면? => 재검증
- max-age가 지났다고 해서 캐시가 바로 완전히 사라지지는 않음
- 이때 브라우저는 서버에 조건부 요청(Conditional Request)을 통해 캐시가 유효한지를 '재검증(Revalidation)'하는 과정 수행
- 재검증의 결과로 브라우저의 캐시가 여전히 유효하다면 새로 받아오지는 않고 서버에서 [304 Not Modified]를 내려줌
- 이 응답은 HTTP 본문(body)이 없기 때문에 매우 빠름 (필요 크기: 324바이트)
캐시 재검증(조건부 요청)을 위한 헤더: If-None-Match와 If-Modified-Since
If-None-Match
브라우저에 캐싱된 리소스의 ETag
값과 서버에 있는 리소스의 ETag
값이 동일한지 확인
If-Modified-Since
캐싱된 리소스의 Last-Modified
시점 후에 서버의 해당 리소스가 변경되었는지 확인
ETag
와 Last-Modified
의 값은 기존에 받았던 리소스의 응답 헤더에 있는 값을 사용
=> 이러한 재검증(조건부 요청) 과정을 거쳤을 때 캐시가 유효하지 않으면 서버는 새로운 데이터(body)와 적절한 상태 코드를 바로 내려줌
- 추가 HTTP 요청 필요 없이 조건부 요청으로 확인한 후 바로 내려주기 때문에 효율적
- 만약 max-age가 0초라면 서버에서 의도한 것은 브라우저가 새로운 리소스를 매번 내려 받는 것
- 하지만 일부 '모바일 브라우저'의 경우 브라우저를 껐다 켜야만 리소스가 만료되게 하는 경우가 있음
- 이는 네트워크 요청을 아끼고 사용자에게 더 좋은 웹 경험을 제공하기 위해서라고 함
=> 이 경우에는 브라우저를 껐다 켜거나, 아래에서 소개할 no-store를 사용한다.
no-cache와 no-store
no-cache
대부분의 브라우저에서 max-age=0과 동일
캐시를 저장은 하지만 캐시를 사용할 때마다 서버에 재검증(유효한지 검증) 요청을 보내야 함
no-store
캐시를 절대 하지 말라는 뜻
캐시를 만들어서 저장조차 하지 말라는 가장 강력한 Cache-Control 값
no-store를 사용하면 브라우저는 어떤 경우에도 저장소에 리소스를 저장하지 않음
캐시가 위치하는 곳
- CDN과 같은 중간 서버를 사용하면 캐시가 여러 곳에 생길 수 있음
- 예: 서버가 가지고 있는 응답을 CDN이 캐시, CDN의 캐시된 응답을 브라우저가 다시 캐시
- 가끔 중간 서버나 CDN이 여러 개 있는 경우도 발생
- 이때 전체 캐시를 날리려면 중간 서버의 각각에 대해 캐시를 삭제해주어야
=> 이렇게 한번 저장된 캐시는 삭제가 어렵기 때문에 Cache-Control의 max-age 값은 신중히 설정해야 함
Cache-Control 헤더의 public과 private
- 중간 서버(예: CDN)가 특정 리소스를 캐시 가능한지 여부 지정
public
모든 중간 서버와 모든 사람이 캐시를 저장할 수 있음
private
가장 끝에 있는 사용자 브라우저만 캐시를 저장할 수 있음
기존의 max-age와 조합해서 사용하기 위해 컴마(,)로 연결해서 Cache-Control: public, max-age=86400
식으로 조합 가능
s-maxage
- 중간 서버에서만 적용되는 max-age 값 설정 시 사용
- 예:
Cache-Control: s-maxage=31536000, max-age=0
- 중간 서버인 CDN에서는 1년 캐시되지만, 브라우저에서는 매번 재검증 요청 보내도록 설정
Cache-Control 사용 예시 (토스)
리소스의 성격에 따라 Cache-Control 헤더 값 조절
HTML 파일
-
배포가 새로 될 때마다 내용이 바뀌는 경우
-
이때 브라우저는 이 HTML 파일을 불러올 때마다 배포가 새로 되었는지 확인해야 함 => 매번 서버에 재검증 요청 필요
- 하지만 새로 배포된 게 없다면 기존 것을 그대로 사용해야 함 => 캐시도 필요
=> Cache-Control
값으로 max-age=0, s-maxage=3153600
설정
-
1년 간 캐시하되, 새 배포를 대비해서 HTML 파일을 가져올 때마다 서버에 재검증을 요청, 그 사이에 새 배포가 있었다면 캐시를 쓰지 않고 새로운 HTML 파일을 내려받음
-
CDN은 HTML 파일에 대한 캐시를 계속 가지고 있으면서 새 배포가 있을 때마다 CDN Invalidation을 진행해서 CDN도 서버에서 새로운 HTML 파일을 받아오도록 함
JS, CSS 파일
- Javascript나 CSS 파일은 웹 서비스를 새로 빌드할 때마다 생김
- 관리 방식: 임의의 버전 번호를 URL에 포함시켜 각 빌드 결과물마다 고유한 URL을 가지도록 설정
- 이렇게 해두면 같은 URL을 가진 리소스의 경우 새로 배포가 일어나지 않는 한 내용이 바뀔 수 없음
- 이러한 경우 max-age의 최대치인 1년(31536000)을 설정해두고 캐시에 저장된 JS 파일을 계속 사용
자세한 캐시 설정의 장점
- 사용자 브라우저가 HTTP 리소스를 더 빠르게 로드 가능
- 개발자는 요청/응답 사이에서 트래픽 비용 절감
참고자료
웹 캐시 똑똑하게 다루기: 토스테크