4 분 소요

캐시 기본 동작 (cache-control 헤더)

  • 서버는 cache-control 헤더에 캐시가 유효한 시간(초)을 담아서 응답한다.
  • 웹 브라우저는 내부에 있는 캐시 저장소에 서버의 응답 결과(캐시가 유효한 시간)를 저장한다.
  • 두 번째 요청 부터는 캐시 유효시간 검사 후,
  • 캐시가 유효하다면 서버에 요청하지 않고 캐시 저장소에서 바로 가져올 수 있다.

캐시가 없을 때

  • 데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운로드 받아야 한다.
  • 인터넷 네트워크는 매우 느리고 비싸다.
  • 브라우저 로딩 속도가 느리다.
  • 느린 사용자 경험

캐시 적용

  • 캐시 덕분에 캐시 가능 시간동안 네트워크를 사용하지 않아도 된다.
  • 비싼 네트워크 사용량을 줄일 수 있다.
  • 브라우저 로딩 속도가 매우 빠르다.
  • 빠른 사용자 경험

캐시 시간 초과

  • 캐시가 유효 시간이 초과되었다면
  • 서버를 통해 데이터를 다시 조회한다.
  • 서버의 응답 결과(캐시가 유효한 시간)를 다시 캐시에 저장한다. (캐시를 갱신한다.)
  • 이때 다시 네트워크 다운로드가 발생한다.

검증 헤더와 조건부 요청 - 1

캐시 유효시간이 초과해서 서버에 다시 요청하면 다음 두 가지 상황이 나타난다.

  1. 서버에서 기존 데이터를 변경한 경우
  2. 서버에서 기존 데이터를 변경하지 않은 경우

캐시 만료 후에도 서버에서 기존 데이터를 변경하지 않은 경우

  • 생각해보면 데이터를 전송하는 대신에 저장해 두었던 캐시를 재사용 할 수 있다.
  • 단, 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있는 방법이 필요하다!

검증 헤더(if-modified-since, Last-Modified 헤더) 추가

  • 서버는 Last-Modified 헤더에 데이터가 마지막으로 수정된 시간 정보를 담아서 응답한다.
  • 웹 브라우저는 응답 결과(cache-control: 유효 시간, Last-Modified: 데이터 최종 수정일)를 캐시에 저장한다.
  • 캐시의 유효 시간이 초과 되었을 때, 웹 브라우저는 if-modified-since 헤더에 캐시가 가지고 있는 데이터 최종 수정일 정보를 담아서 서버에게 요청한다.
  • 서버의 데이터 최종 수정일과 if-modified-since 값이 같다면, 304 Not Modified를 응답한다.
    (HTTP Body는 제외하고 Header만 전송한다. -> 네트워크 부하를 확 줄일 수 있다!)
  • 웹 브라우저는 304 Not Modified를 받았을 때, 캐시를 다시 세팅한 뒤에 (cache-control, Last-Modified 갱신)
  • 캐시에서 데이터를 조회하여 사용한다.

🔥 if-modified-since, Last-Modified 정리

  • 캐시 유효 시간이 초과해도, 서버의 데이터가 갱신되지 않으면
  • 304 Not Modified + 헤더 메타 정보만 응답(바디X)
  • 클라이언트는 서버가 보낸 응답 헤더 정보로 캐시의 메타 정보를 갱신
  • 클라이언트는 캐시에 저장되어 있는 데이터 재활용
  • 결과적으로 네트워크 다운로드가 발생하지만 용량이 적은 헤더 정보만 다운로드
  • 매우 실용적인 해결책

검증 헤더와 조건부 요청 - 2

검증 헤더

  • 캐시 데이터와 서버 데이터가 같은지 검증하는 데이터
  • Last-Modified, ETag

조건부 요청 헤더

  • 검증 헤더로 조건에 따른 분기
  • If-Modified-Since: Last-Modified 사용
  • If-None-Match: ETag 사용
  • 조건이 만족하면 200 OK
  • 조건이 만족하지 않으면 304 Not Modified

예시: If-Modified-Since: 이후에 데이터가 수정되었으면?

  • 데이터 미변경 예시
    - 캐시: 2020년 11월 10일 10:00:00 vs 서버: 2020년 11월 10일 10:00:00
    - 304 Not Modified, 헤더 데이터만 전송 (BODY 미포함)
    - 전송 용량 0.1M (헤더 0.1M, 바디 1.0M)
  • 데이터 변경 예시
    - 캐시: 2020년 11월 10일 10:00:00 vs 서버: 2020년 11월 10일 11:00:00
    - 200 OK, 모든 데이터 전송 (BODY 포함)
    - 전송 용량 1.1M (헤더 0.1M, 바디 1.0M)

Last-Modified, If-Modified-Since 단점

  • 1초 미만(0.x초) 단위로 캐시 조정이 불가능
  • 날짜 기반의 로직 사용
  • 데이터를 수정해서 날짜가 다르지만, 같은 데이터를 수정해서 데이터 결과가 똑같은 경우(A->B 수정 이후 B->A 다시 수정)에도 전체 데이터를 전부 다시 다운로드 한다.
  • 서버에서 별도의 캐시 로직을 관리하고 싶은 경우
    - 예) 스페이스나 주석처럼 크게 영향이 없는 변경에서 캐시를 유지하고 싶은 경우

ETag, If-None-Match

  • ETag(Entity Tag)
  • 캐시용 데이터에 임의의 고유한 버전 이름을 달아둠
    - 예) ETag: “v1.0”, ETag: “a2jiodwjekjl3” (파일에 해시 알고리즘을 적용한 값)
  • 데이터가 변경되면 이 이름을 바꾸어서 변경함 (Hash를 다시 생성)
    - 예) ETag: “aaaaa” -> ETag: “bbbbb”
  • 진짜 단순하게 ETag만 보내서 같으면 유지, 다르면 다시 받기!

ETag를 활용한 방법

  • 클라이언트의 요청에 서버는 ETag 헤더를 포함하여 응답한다.
  • 웹 브라우저는 응답 결과(ETag 값✨)를 캐시애 저장한다.
  • 두 번째 요청 시에 캐시 시간이 초과 되었다면, 클라이언트는 If-None-Match 헤더에 캐시가 가지고 있는 ETag 값을 포함하여 요청한다.
  • 서버가 가지고 있는 ETag 값과 같다면 304 Not Modified로 HTTP Body 없이 Header만 전송한다.
  • 웹 브라우저는 304를 받으면 캐시를 갱신한 뒤에 캐시에 있는 데이터를 재사용한다.

🔥 ETag, If-None-Match 정리

  • 진짜 단순하게 ETag만 서버에 보내서 같으면 유지, 다르면 다시 받기!
  • 캐시 제어 로직을 서버에서 완전히 관리 🌟
  • 클라이언트는 단순히 이 값을 서버에 제공(클라이언트는 캐시 메커니즘을 모름)
  • 예)
    - 서버는 배타 오픈 기간인 3일 동안 파일이 변경되어도 ETag를 동일하게 유지
    - 애플리케이션 배포 주기에 맞추어 ETag 모두 갱신

캐시와 조건부 요청 헤더

Cache-Control 🌟

캐시 지시어 (directives)

Cache-Control: max-age

캐시 유효 시간, 초 단위

Cache-Control: no-cache

데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증하고 사용 (if-modifed-since, If-None-Match 등등 이용)

Cache-Control: no-store

데이터에 민감한 정보가 있으므로 하드디스크 등에 저장하면 안됨
(메모리에서 사용하고 최대한 빨리 삭제)

Pragma

캐시 제어 (하위 호환)

  • Pragma: no-cache
  • HTTP 1.0 하위 호환
  • 지금은 거의 사용되지 않음

Expires

캐시 만료일을 날짜로 지정(하위 호환)

  • expires: Mon, 01 Jan 1990 00:00:00 GMT
  • 캐시 만료일을 정확한 날짜로 지정
  • HTTP 1.0 부터 사용
  • 지금은 더 유연한 Cache-Control: max-age 권장
  • Cache-Control: max-age와 함께 사용하면 Expires는 무시

검증 헤더와 조건부 요청 헤더 정리

검증 헤더 (Validator)

  • ETag: “v1.0”, ETag: “asid93jkrh2l”
  • Last-Modified: Thu, 04 Jun 2020 07:19:24 GMT

조건부 요청 헤더

  • If-Match, If-None-Match: ETag 값 사용
  • If-Modified-Since, If-Unmodified-Since: Last-Modified 값 사용

프록시 캐시

원 서버 직접 접근

스크린샷 2022-06-13 오전 2 50 46

  • 한국에 있는 클라이언트가 미국에 있는 원 서버에게 요청한다면, 응답 받는데 0.5초가 걸린다.

프록시 캐시 도입

스크린샷 2022-06-13 오전 2 52 08

  • 웹 브라우저는 한국에 있는 프록시 캐시 서버에 요청하면, 응답 받는데 0.1초가 걸린다.

스크린샷 2022-06-13 오전 2 52 20

  • 중간에서 공용으로 사용하는 캐시를 public 캐시라고 하고, 웹 브라우저나 로컬에 저장되는 캐시를 private 캐시라고 한다.

Cache-Control

캐시 지시어 (directives) - 기타

Cache-Control: public

  • 응답이 public 캐시에 저장되어도 된다는 의미

Cache-Control: private

  • 응답이 해당 사용자만을 위한 것임, private 캐시에 저장해야 함 (기본값)

Cache-Control: s-maxage

  • 프록시 캐시에만 적용되는 max-age

Age: 60 (HTTP 헤더)

  • 오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간(초)

캐시 무효화

캐시를 적용하지 않아도 웹 브라우저가 임의로 캐시를 해버리기도 한다.
캐시가 되면 절대로 안되는 정보라면 아래 키워드를 모두 넣어서 캐시 무효화를 할 수 있다.

Cache-Control: 확실한 캐시 무효화

Cache-Control: no-cache

  • 데이터는 캐시해도 되지만, 항상 원 서버에 검증하고 사용(이름에 주의!)

Cache-Control: no-store

  • 데이터에 민감한 정보가 있으므로 저장하면 안됨 (메모리에서 사용하고 최대한 빨리 삭제)

Cache-Control: must-revalidate

  • 캐시 만료후 최초 조회시 원 서버에 검증해야함
  • 원 서버 접근 실패시 반드시 오류가 발생해야함 - 504(Gateway Timeout)
  • must-revalidate는 캐시 유효 시간이라면 캐시를 사용함

Pragma: no-cache

  • HTTP 1.0 하위 호환


💛 개인 공부 기록용 블로그입니다. 👻

맨 위로 이동하기