[Network] 캐시 (cache)

hi·2022년 8월 30일
0

캐시가 없을 때

1. 요청 
GET /star.jpg

2. 1.1M 응답 (용량 가정)

HTTP 헤더 : 0.1M
HTTP 바디 : 1.0M

3. 요청 2
GET /star.jpg

4. 응답 
1.1M 전송
  • 데이터가 변경되지 않아도 계속 네트워크를 통해 데이터를 다운로드 받음
  • 인터넷 네트워크는 매우 느리고 비쌈
  • 브라우저 로딩 속도가 느림

캐시 적용시

1. 요청 
GET /star.jpg

2. 1.1M 응답
cache-control: max-age=60  //header, 캐시 유효 시간 (초)

3. 응답 결과 브라우저 캐시에 저장

4. 요청 2 
GET /star.jpg

5. 캐시에서 조회
  • 캐시 가능 시간동안 네트워크를 사용하지 않아도 됨
  • 비싼 네트워크 사용량을 줄일 수 있다
  • 브라우저 로딩 속도가 매우 빠름

캐시 시간 초과시

  • 서버를 통해 데이터를 다시 조회하고, 캐시를 갱신
  • 다시 네트워크 다운로드 발생

but, 기존 데이터가 변경되지 않았다면?
다시 다운로드 할 필요 X 이를 위해 검증 헤더 사용


검증 헤더 & 조건부 요청

  • 검증 헤더

    • 캐시 데이터와 서버 데이터가 같은지 검증하는 데이터
    • Last-Modified , ETag
  • 조건부 요청 헤더

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

Last-Modified & if-modified-since

1. 요청

2. 1.1M 응답

cache-control: max-age=60
Last-Modified: xxxx년 xx월 xx일 23:21:33 //응답 캐시에 저장 [검증 헤더]

3. 응답 결과(데이터 최종 수정일) 캐시에 저장

4. 캐시 시간 초과

5. 요청 2

GET /star.jpg
if-modified-since: xxxx년 xx월 xx일 23:21:33 //캐시가 가지고 있는
											데이터 최종 수정일 [조건부 요청]

6. 서버의 데이터 최종 수정일과 비교 -> 동일 -> HTTP Body를 제외한 0.1M 응답

HTTP/1.1 304 Not Modified 👈
..
cache-control: max-age=60
Last-Modified: xxxx년 xx월 xx일 23:21:33

..
// HTTP Body 제외


7. 캐시 갱신 후 셋팅 -> 캐시에서 조회하여 사용

캐시 유효 시간이 초과해도 서버의 데이터가 갱신되지 않으면
304 Not Modified + 헤더 메타 정보만 응답 (바디 x)

  • 클라이언트는 서버가 보낸 응답 헤더 정보로 캐시의 메타 정보 갱신
  • 클라이언트는 캐시에 저장되어 있는 데이터 재활용
  • 결과적으로 네트워크 다운로그가 발생하지만 용량이 적은 헤더 정보만 다운로드
  • 매우 실용적인 해결책

단점

  • 1초 미만 단위로 캐시 조정 불가
  • 날짜 기반의 로직 사용
  • 데이터를 수정하여 날짜는 다르지만, 같은 데이터로 수정하여 최종 결과가 같은 경우
  • 서버에서 별도의 캐시 로직을 관리하고 싶은 경우
    • space, 주석처럼 크게 영향이 없는 변경에서 캐시를 유지하고 싶은 경우

이 단점을 보완한 것이 👇

ETag & if-None-Match

  • ETag (Entity Tag)
  • 캐시용 데이터에 임의의 고유한 버전 이름을 달아둠
    ex) ETag: "v1.0"
    ETag: "a2jiodwjekji3" //Hash 결과로 생성
  • 데이터가 변경되면 이 이름을 변경 (Hash 재생성)
  • 단순하게 ETag만 보내서 같으면 유지, 다르면 재다운로드
1. 요청

2. 1.1M 응답 

cache-control: max-age=60
ETag: "aaaaa"
Content-Length: ...

3. 응답 결과(ETag) 캐시에 저장
4. 캐시 시간 초과

5. 요청 2

GET /star.jpg
if-None-Match: "aaaaa" //캐시가 가지고 있는 ETag

5. 서버의 데이터 ETag와 비교 -> 동일 -> HTTP Body를 제외한 0.1M 응답

HTTP/1.1 304 Not Modified 👈
..
cache-control: max-age=60
ETag: "aaaaa"
..
// HTTP Body 제외

6. 캐시 갱신 후 셋팅 -> 캐시에서 조회하여 사용
  • 캐시 제어 로직을 서버에서 완전히 관리
  • 클라이언트는 단순히 이 값을 서버에 제공
    ex) 애플리케이션 배포 주기에 맞추어 ETag 모두 갱신


캐시 제어 헤더

  • Cache-Control : 캐시 제어
  • Pragma : 캐시 제어 (하위 호환)
  • Expires : 캐시 유효 기간 (하위 호환)

Cache-Control

캐시 지시어

  • Cache-Control: max-age
    캐시 유효 시간 (초 단위)

  • Cache-Control: no-cache
    데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증하고 사용

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

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


캐시 지시어 - 기타

  • Cache-Control: public
    응답이 public 캐시에 저장되어도 됨

  • Cache-Control: private
    응답이 해당 사용자만을 위한 것. private 캐시에 저장해야 함 (기본값)

  • Cache-Control: s-maxage
    프록시 캐시에만 적용되는 max-age

  • Age: 60 (HTTP헤더)
    origin 서버에서 응답 후 프록시 캐시 내에 머문 시간 (초)


Pragma

캐시 제어(하위 호환)

Pragma : no-cache
  • HTTP 1.0 하위 호환

Expires

캐시 만료일 지정(하위 호환)

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

🔎 프록시 캐시

원(origin) 서버에 직접 접근하는 경우

프록시 서버 도입 후

  • private 캐시 : 웹 브라우저 , local에 저장되는 캐시
  • 최초의 요청은 캐시가 없어 느리지만, 두번째 요청부터는 빠르게 조회

유튜브에서 외국 영상 중 인기 많은 것들과 아주 마이너한 영상의 로딩 속도 차이도 이 때문이라고 한다 😲

Cache-Control

캐시 지시어 - 기타

  • Cache-Control: public
    응답이 public 캐시에 저장되어도 됨

  • Cache-Control: private
    응답이 해당 사용자만을 위한 것. private 캐시에 저장해야 함 (기본값)

  • Cache-Control: s-maxage
    프록시 캐시에만 적용되는 max-age

  • Age: 60 (HTTP헤더)
    origin 서버에서 응답 후 프록시 캐시 내에 머문 시간 (초)


캐시 무효화

확실한 캐시 무효화 응답 (모두 넣기)

Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache (HTTP 1.0 하위 호환)


🔎 no-cache vs must-revalidate


0개의 댓글