캐시가 없을 때

  1. 웹 브라우저에서 GET/star.jpg 요청
  2. 서버에서 헤더(0.1M) + 바디(1.0M) 데이터를 전송함 -> 총 1.1M
  3. 웹 브라우저에서 다시 start 요청
  4. 2번 반복 -> 1.1M 데이터가 다시 전송됨

데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운로드 받아야한다

인터넷 네트워크는 매우 느리고 비쌈

브라우저 로딩 속도가 느림 -> 느린 사용자 경험

캐시 적용

  1. 웹 브라우저에서 GET/star.jpg 요청

  2. 서버에서 헤더(0.1M) + 바디(1.0M) 데이터를 전송함 -> 총 1.1M

    이 때, 헤더에 cache-control: max-age=60 을 같이 보내서 캐시 만료시간 60초를 같이 보냄

  3. 서버에서 보낸 데이터를 브라우저 캐시에 저장 (만료시간 60초)

  4. 60초가 지나지 않았을 때, 다시 start를 요청하면, 우선 캐시를 뒤져서 start를 찾아내서 보여줌

캐시 덕분에 캐시 가능 시간동안 네트워크를 사용하지 않아도 된다

비싼 네트워크 사용량을 줄일 수 있다

브라우저 로딩속도가 빠르다 -> 빠른 사용자 경험

캐시를 적용했는데 시간이 초과됐다면?

  1. 60초 초과
  2. 다시 웹 브라우저가 start를 요청함
  3. 서버에서 헤더 + 바디 1.1M 를 다시 전송해줌
  4. 응답결과 다시 캐시 저장

캐시 유효시간이 초과하면, 서버를 통해 다시 조회하고 캐시 갱신 -> 네트워크 다운로드가 다시 발생

검증 헤더와 조건부 요청

캐시 유효시간이 초과 해서 서버에 다시 요청하면 2가지 상황 발생

  1. 서버에서 기존 데이터를 변경했을 경우, 진짜 바뀌어서 나옴(노란별 -> 초록별)
  2. 서버에서 데이터 변경을 안했을 경우 안바뀜(노란별 -> 노란별)

캐시 시간초과

캐시 만료후에도 서버에서 데이터를 변경하지 않았을 경우, 서버에서 데이터를 전송하는 대신 저장해 두었던 캐시를 재사용 할 수 있다.

단, 클라이언트의 캐시 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있는 방법이 필요하다

1. Last-Modified, if-modified-since 사용

  1. 서버에서 응답을 보낼 때 Last-Modified를 보내서, 데이터의 최종 수정일을 같이 응답함 (헤더 + 바디 1.1M)

    HTTP/1.1 200 OK
    #생략
    cache-control: max-age=60
    Last-Modified: 2020sus 11월 10일 10:00:00 #원래는 이런 형식 아님.. 일단.. 
    #길이
    
    djfkl;ajkfldjfals#바디
    
  2. 이 응답 결과를 캐시에 저장

  3. 캐시 시간이 초과 되어 다시 서버에 요청할 경우, 요청 헤더에 if-modified-since:2020년 11월10일 10:00:00 을 같이 보냄

    날짜는 캐시에 저장되어있는 데이터의 최종 수정일

  4. 만약 서버에 있는 데이터의 최종 수정일과 요청 헤더의 날짜가 같은 경우 -> 아직 수정되지 않은 데이터

  5. 이럴경우..

    HTTP/1.1 304 Not Modified
    #생략
    cache-control: max-age=60
    Last-Modified: 2020sus 11월 10일 10:00:00 #원래는 이런 형식 아님.. 일단.. 
    #길이 생략
    

    ``` 304 응답과 바디가 없는 응답을 보냄 -> 이때, 헤더값만 보내니 0.1M의 전송만 함!

  6. 이 응답 결과를 다시 캐시에 저장하여 캐시의 유효 시간을 갱신함 (다시 60초로)

  7. 브라우저는 캐시의 데이터를 사용해서 보여줌 ```

정리

  • 캐시 유효시간이 초과해도 서버의 데이터가 갱신되지 않으면 304 + 헤더의 정보만 응답으로 보냄
  • 클라이언트는 캐시에 저장되어 있는 데이터 재활용
  • 네트워크 다운로드가 발생하지만, 용량이 적은 헤더만 다운로드하게 된다.
  • 매우 실용적인 방법
  • 만약, 데이터가 변경되었다면 200 ok 응답과 함께 바디에 바뀐 데이터를 넣어서 정보를 보낸다.
  • 단점
    • 1초 미만 단위로 캐시 조정 불가
    • 날짜 기반의 로직 사용
    • 데이터를 수정해서 날짜가 다르지만, 같은 데이터를 수정해서 데이터 결과가 똑같은 경우..
    • 서버에서 별도의 캐시 로직을 관리하고 싶은 경우는 사용 불가

2. If-None-Match, ETag 사용

  • 서버에서 캐시를 컨트롤 할 수 있다.

  • 캐시용 데이터에 임의의 고유한 버전 이름을 달아둠

    ex) ETag: “v1.0”, ETag: “adsfesaefa”

  • 데이터가 변경되면 이 이름을 바꾸어서 변경함 (Hash를 다시 생성)

  • 단순하게, ETag만 보내서 같으면 유지, 다르면 다시 받기

  1. 서버에서 응답에 ETag 생성해서 보내줌
HTTP/1.1 200 OK
#생략
cache-control: max-age=60
ETag: "aaaaaaaaaaaa"
#길이

djfkl;ajkfldjfals#바디
  1. 브라우저 캐시에 저장
  2. 만약 캐시 시간이 초과된 경우 요청 헤더에 If-None-Match: "aaaaaaaaaa"를 보내줌
  3. 서버에서 데이터의 이름을 확인 후, 데이터가 수정되지 않았으면 304 + 바디 없음으로 응답 보냄
  4. 브라우저 캐시 갱신

정리

  • 캐시 제어 로직을 서버에서 완전히 관리한다.
  • 클라이언트는 단순히 이 값을 서버에 제공한다.

캐시와 조건부 요청 헤더

1. Cache-Control

  • Cache-Control: max-age=22 -> 캐시 유효시간, 초단위
  • Cache-Control: no-cache
    • 데이터는 캐시해도 되지만, 항상 원 서버에 검증하고 사용 (if-none-match 이런거를 원래서버에 꼭 검증해라.)
  • Cache-Control: no-stroe -> 데이터에 민감한 정보가 있으므로 저장하지 마라
  • 얘만 있으면 밑에 pragma, expires 안써도됨, 밑애 애들은 Http 1.0 하위호환으로 쓰임

2. Pragma

  • Pragma: no-cache

3. Expires

  • 캐시 만료일 지정, 날짜로 지정함
  • 지금은 max-age를 더 잘씀
  • max-age와 같이 사용시 expires는 무시됨

4. 검증 헤더와 조건부 요청 헤더

  • 검증헤더
    • ETag
    • Last-Modified
  • 조건부 요청헤더
    • If-Match, If-None-Match: ETag 값 사용
    • If-Modified-Since, If-Unmodified-Since : Last-Modifed 값 사용

프록시 캐시

만약에 한국에서 미국에 있는 원래 서버에 직접 접근할 시, 시간이 오래 걸림

한국 - 한국 프록시 캐시서버 - 미국 원래서버

이런 식으로 거쳐간다면, 한국 사람들이 사용하는 데이터들은 한국 프록시 캐시서버에 저장되기 때문에

미국 서버에 직접 접근하는 것 보다 빠르게 데이터를 받을 수 있다.

이경우, 보통 클라이언트 들은 private 캐시 저장소를, 프록시 캐시서버는 public 캐시 저장소를 가지고 있음

캐시 지시어?

  • Cache-Control: public - 응답이 public 캐시에 저장되어도됨
  • Cache-Control:private - 응답이 해당 사용자들만 위한것, 기본 값, 프록시 캐시로 저장되면 안됨
  • Cache-Control: s-maxage - 프록시 캐시에만 적용되는 max-age
  • Age:60 - 원래 서버에서 응답 후 프록시 캐시 내에 머문 시간 (초)

캐시 무효화

1. Cache-Control: no-cache

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

  • 만약, 캐시 서버에 요청했는데, no-cache + ETag조건이 있다면?

    • 네트워크 장애가 발생하지 않을 경우,

      클라이언트가 캐시를 요청하면 프록시 캐시 서버를 거쳐서 원서버에서 캐시 검증 후 304나 200 응답… (프록시에서 캐시 검증을 안함!)

    • 만약 프록시 서버와 원래 서버 사이에 네트워크 단절이 일어났다면

      원 서버에 접근할 수 없는 경우 캐시 서버 설정에 따라 데이터를 반환해 줄 수 있음 프록시 캐시에 남아있는 옛날 데이터.. 200 응답으로..

2. Cache-Control: no-stroe

  • 데이터에 민감한 정보가 있으므로 저장하면 안됨

3. Cache-Control: must-revalidate

  • 캐시 만료 후 최초 조회시 원 서버에서 검증해야함

  • 원 서버 접근 실패시 반드시 오류가 발생해야함 - 504(Gateway Timeout)

  • 캐시 유효시간이라면 캐시를 사용함

  • 만약, 캐시 서버에 요청을 했는데 must-revalidate + ETag 조건이 있다면!

      1. 브라우저가 프록시 캐시에 데이터 요청

      2. 만약에 원 서버와 프록시 캐시 서버 사이에 네트워크 단절이 일어났다면?

      3. 원 서버에 접근할 수 없으니 오류가 발생해야함!

        ex) 통장 잔고를 프록시 캐시에 있는 정보로 보내주면 안됨 -> 예전 정보일 수 있으니..

      4. 프록시 캐시에서 504 에러로 응답

4. Pragma: no-cahce

  • HTTP 1.0 하위 호환