인터넷 cache

강정우·2023년 11월 26일
0

네트워크

목록 보기
21/32

Cache

  • 우선 캐시가 없을 때 상황을 가정해보자.
    사용자가 서버에 1.1M의 이미지를 요청하고 받았는데 또 요청하면 또 1.1M의 이미지를 다운받아야한다. 이는 사용자로 하여금
  1. 데이터가 변경되지 않았음에도 계속 네트워크를 통해서 데이터를 다운받야아한다.
  2. 인터넷 네트워크는 매우 느리고 비싸다.
  3. 브라우저 로딩 속도가 느리다.
  4. 느린 UX를 제공한다.
  • 이제 사용자가 요청을 할 때 서버에서 아래와같이 cache-control이라는 응답헤더를 만들어서 내려주면

  • 클라이언트는 이를 캐시 저장소에 저장해두었다가 두번째 요청할 땐 캐시 메모리를 뒤져서 아직 유효하다면 그냥 캐시에서 바로 가져오면 된다.

  • 그럼 이제 또 문제가 생기는데 캐시시간이 초과된다면 똑같은 값을 서버를 통해 전체를 다시 데이터를 다운받고 캐시를 갱신한다.
    이는 다시 네트워크 다운로드가 발생한다.
    그럼 이 바보같은 상황을 어떻게 해결할까?

검증 헤더(Last-Modified, ETag)와 조건부 요청(if-modified-since, if-None-Match)

  • 캐시 유효기간이 초과해서 서버에 다시 요청을 하면 값이 바뀌든 안 바뀌든 두가지 상황이 나타난다.

서버에서 값이 바뀌었을 때

  • 이때는 값을 받아서 캐시를 갱신하고 최신 데이터를 고객에게 보여주는게 맞다.

값이 그대로일 때

  • 문제는 이때인데 굳이 똑같은 데이터를 다시 다운 받을 필요가 없다.
    그냥 있는 캐시를 재사용하면 된다.

Last-Modified

  • 다만 이때, 클라이언트와 서버의 데이터가 같다는 사실 확인만이 필요한데 이때 사용하는 방법이 검증헤더이다.

  • 바로 Last-Modified 즉 마지막 수정시간을 보고 확인할 수 있다.
    그래서 캐시 시간이 다시 초과하여 요청 할 때 req header에 if-modified-since: 값을 넣어서 요청하면
    서버에서는 이제 데이터 최종 수정일과 비교하여 검증을 할 수 있다.

  • 그러면 이제 서버에서는 304 not modified라고 내려준다.

  • 그럼이제 헤더에 값만 왔다갔다하기 때문에 실제 이미지 값이 들어있는 http body가 없기 때문에 굉장히 가볍고 빠르고, 싸게 소통하여 네트워크 부하를 확 줄일 수 있다.

  • 참고로 개발자 도구의 네트워크 탭을 봤을 때 Status가 찐한게 있고 연한게 있는데 연한거는 그냥 cache에서 가져온 것이다.

ETag

  • 위 Last-Modified, If-Modified-Since 조합의 단점이 존재한다.
  1. 1초 미만 단위로 캐시 조정이 불가능하다.
  2. 날짜 기반의 로직을 사용한다. -> 데이터를 수정해서 날짜가 다르지만, 다시 원복해서 데이터 결과가 똑같은 경우에는 무방비하다.
  3. 서버에서 별도의 캐시 로직을 관리하고 싶은 경우
    • 스페이스나 주석처럼 크게 영향이 없는 변경에서 캐시를 유지하고 싶은 경우
  • 그래서 서버에서 캐시 메터니즘을 컨트롤하고 싶을 때 사용하는 방법이 바로 ETag이다.
    여기서 E는 entity를 뜻하는데 이 캐시용 데이터에 임의의 고유한 버전을 달아놓을 수 있다.

  • 예를들어 캐시용 데이터의 임의의 고유한 버전 이름을 달아두는데 이때 이름을 해당 데이터의 해쉬 값을 넣을 수도 있다. 그럼 데이터를 다시 원복해도 해쉬 값을 똑같을 테니까.
    그래서 데이터가 바뀐다면 해쉬값도 바뀔거고, 무튼 그래서 해당 버전이름(ETag)만 주고받으면서 조건부 요청을 구현하는 것이다.

  • 이때 클라이언트는 진짜 블랙박스 역할만 하여 서버에 값을 전달하는 기능만한다.

    • 예) 어플리케이션 배포 주기에 맞춰서 ETag모두 갱신하자.

Cache 제어 헤더

1. Cache-Control: 캐시 제어(directives)

  • Cache-Control: max-age

    • 캐시 유효 시간, 초 단위 입력
  • Cache-Control: no-cache

    • 데이터는 캐시해도 되지만, 항상 조건부 요청을 통해서 origin 서버에 검증하고 사용
    • 그런데 가끔 어떤 서버에는 원서버와 연결이 끊기면 그냥 프록시 서버의 데이터와 비교 후 200ok를 처리하는 서버도 있음. 근데 이게 no-cache의 정책이기도 해서 뭐라고는 못 함 이때 문제를 해결하기위해 아래의 must-revalidate가 있음.
  • 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 헤더)

    • 오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간
  1. Pragma: 캐시 제어 (Cache-Control의 하위호환)

    • Pragma: no-cache
    • HTTP 1.0 하위 호환
  2. Expires: 캐시 유효 기간 (Cache-Control의 하위호환)

    • expires: {GMT 시간}
    • 캐시 만료일을 정확한 날짜로 지정
    • HTTP 1.0 이후 버전에서
    • 그런데 Cache-Control: max-age가 더 권장됨
    • 만약 위 컨트롤과 같이 쓰였다면 expires는 무시됨
  3. 검증헤더 (validator)

    • 위에서 한 ETag, Last-Modified
  4. 조건부 요청 헤더

    • If-Match, If-None-Match
    • If-Modified-Since, If-UnModified-Since

Proxy Chache

  • 한국의 클라이언트가 미국에 있는 원 서버에 갔다오려면 꽤 오래걸린다.
    이미지 하나를 받는데 0.5초가 걸린다는 뜻이다.

  • 그래서 대안이 프록시 캐시(CDN 서비스)를 도입하는 것이다.
    그래서 미국 원 서버에서 한국의 어딘가에 프록시 캐시 서버를 만들어 두고 요청을 할 때 이 proxy-cache server에 접근하게 만드는 것이다.

  • 그래서 일반 사람들이 잘 안 보는 기술관련된 외국 영상을 찾아보면 느리지만(원 서버에서 가져와서) 일반사람들이 많이 보는 영상은 로딩이 빠른게 한국의 프록시 서버에서 가져오기 때문이다.
    이는 처음 다운로드 받는 사람이라면 프록시 캐시 서버에 없는 자료이기 때문에 다운 받아와야해서 느린 것이다.

Cache 100% 무효화 응답

  • 상황: 캐시를 적용하지 않아도 웹브라우저들이 GET요청인 경우에는 임의로 캐시를 해버린다.
    이 경우를 heuristic하게 한다고 하는데 그래서 진짜로 캐시를 하면 안 되는 경우에는
    Cache-Control: no-cache, no-store, must-revalidate를 모두 넣어줘야한다.
    또한 과거 http 1.0 브라우저에서 어떤 요청이 들어올 수 있기 때문에 Pragma: no-cache도 넣어줘야한다.
profile
智(지)! 德(덕)! 體(체)!

0개의 댓글