[네트워크] - http header 쪼개기2, cache

EMMA·2022년 2월 11일
0

http header: cache(캐시) 관련 헤더, 정말 중요하다.

운영체제를 공부하다보면 CPU와 메모리 사이에 캐시가 중요한 역할을 한다는 사실을 확인할 수 있는데, http강의에서도 캐시 관련 헤더에 대해 소개되어 반가운(?) 마음이 들었다.

만약 캐시가 없다면, 클라이언트가 서버에 요청하는 데이터가 동일한 내용이라고 해도 계속 새로 다운로드 받아야 한다. 네트워크 속도가 느려지면 브라우저 로딩 속도도 느려지고, 이는 당연히 사용자의 느린 경험으로 연결된다.

그래서 서버가 cache-control: max-age= 60를 포함해서 응답하면, 클라이언트는 데이터를 캐시에 넣고 사용할 수 있다. 그러면 유효 시간(60초) 동안에는 서버로 갈 필요 없이 캐시에서 바로 꺼내 쓰면 되는 것이다.

캐시를 사용하면...

  • 캐시 가능 시간 동안 네트워크를 사용할 필요 없다 (네트워크 사용량 down)
  • 브라우저로딩 속도가 빨라진다 -> 빠른 사용자 경험

📍 1 차로 cache를 잘 썼다 치자. 그런데 그 이후에는?
그럼 만약 유효 시간 60초가 지나고 서버에 다시 데이터를 요청하면 어떻게 될까? 서버는 기존 데이터를 변경하지 않는다. 어느 쪽이든 서버는 또 동일하게
cache-control: max-age= 60 을 포함해서 응답할 것이고, 클라이언트는 다시 데이터를 60초 동안 유효한 상태로 캐시에 저장한다. 결국 네트워크 다운로드가 반복되는 것이다.
(위의 max-age:60은 예시다)

이를 해결하기 위해 검증 헤더를 사용한다. 2가지 방법이 있다.

  1. if-modified-since/if-unmodified-since, last-modified
  2. if-match/if-non-match, ETag
  1. if-modified, last-modified
    : last-modified: 2020년 2월 11일 10:00:00 라고 서버에서 응답하면,
    : 클라이언트는 2번째 요청 시 if-modified-since:2020년 2월 11일 10:00:00을 같이 서버에 보낸다
    : 서버는 날짜를 비교해 변동이 없는 경우 클라이언트 캐시로 리다이렉트 한다
    (http/1.1 304 not modified + message body(아무 내용 없음))
    : 클라이언트는 캐시를 재세팅하고 데이터를 꺼내서 사용한다

  2. if-non-match, ETag(Entity Tag)
    : 캐시용 데이터에 임의의 고유한 버전 이름을 붙여 서버가 보내준다. 버전 이름은 직접 달거나 hash 알고리즘(hash library)를 사용하기도 한다 (데이터를 hash에 넣으면 고유 hash값을 생성해주는데, 데이터 중간 수정과정과 관계 없이 결과물이 똑같으면 똑같은 hash값을 부여 받는다)
    : 클라이언트는 2번째 요청 시 if-non-match:aaa 를 보내고,
    : 서버는 ETag를 비교해 동일한 경우 클라이언트 캐시로 리다이렉트 한다
    (http/1.1 304 not modified + message body(아무 내용 없음))


2번의 가장 큰 장점은 서버가 캐시 제어 로직을 완전히 관리할 수 있다는 점이다. 클라이언트는 ETag 정보만 받기 때문에 캐시 메커니즘을 알 수 없다. 게다가 날짜 기반의 로직을 적용한 1번 방법은 1초 미만 단위의 조정이 불가능하다.

그뿐 아니라, 데이터 최종 날짜는 최종 결과와 관계 없이 건드린 흔적만 생겨도 갱신된다. 그러면 당연히 서버는 다른 데이터로 받아들이고 클라이언트 캐시로 리다이렉트해주지 못한다.


📍 캐시 제어 관련 헤더를 정리해보자

간혹 웹브라우저가 데이터 보고 임의로 캐시에 저장하는 경우가 있기 때문에, 캐시 제어는 중요하다.

<조건부 헤더>

  • cache-control: max-age, 캐시 유효 기간 (초 단위)
  • cache-control: no-cache, 데이터를 캐시하기 전 origin server로부터 검증 필요
  • cache-control: must-revalidate, 데이터를 캐시하기 전 origin server로부터 검증 필요
  • cache-control: no-store, 데이터에 민감한 정보가 있으므로 캐시 저장 불가 (즉, 메모리에서 사용하고 삭제)
  • expires, 캐시 만료일 지정(하위 호환), 하지만 유연성이 떨어져 대부분 max-age 사용 (둘 다 사용하는 경우 max-age 적용이 우선)
  • pragma:no-cache, 하위 호환(http 1.0의 경우 no-cache, no-store 등을 알지 못해 pragma를 통해 호환되도록 해줘야 함)

<검증 헤더>

  • if-modified-since/if-unmodified-since, last-modified
  • if-match/if-non-match, ETag

📍 프록시 캐시

웹브라우저에서 데이터를 서버에 요청할 때, 매번 origin server(원 소스가 있는 서버, 원 서버로 불림)에 접근하려면 시간이 오래 걸린다. 그래서 중간에 프록시 서버를 두고, DNS 등을 조정해서 웹브라우저의 요청이 프록시 서버로 가게 만드는 것이다.
이 때 프록시 서버의 캐시는 public 캐시, 웹브라우저 캐시는 private 캐시라고 한다.


예를 들어, youtube에서 사람들이 잘 안보는 동영상은 로딩 속도가 느린 반면, 조회수가 높은 동영상은 로딩 속도가 빠르다. 이는 해당 동영상이 프록시 서버를 통해 전달되기 때문이다.

클라이언트가 임의로 private 캐시를 사용하는 걸 막기 위해서 캐시 제어(캐시 무효화)는 반드시 필요한데, 보통 아래 헤더들을 추가하면 제어가 잘 된다.
cache-control: no-cache, no-store, must-revalidate
pragma: no-cache

추가로 넣을 수 있는 제어 헤더는 아래와 같다.

  • cache-control: public, public 캐시에 저장해도 됨
  • cache-control: private, private 캐시에만 저장해야 함(public 캐시 저장은 불가)
  • cache-control: s-maxage, public 캐시에만 적용되는 max-age
  • age: 60, 원 서버에서 응답 후 프록시 캐시 내 머문 시간 (단위: 초)

*제어 헤더 중, no-cache와 must-revalidate의 차이는?

순간적인 네트워크 단절로 인해 원 서버에 접근하기 어려운 경우, cache-control:no-cache 는 프록시 서버에서 처리할 수 있다. 과거 데이터라도 전달해야 하는 경우가 있으므로.
반면 cache-control:must-revalidate 는 원 서버의 검증을 무조건 받아야 하기 때문에 504 gateway timeout 이라는 오류를 보낸다.



내용 출처: 모든 개발자를 위한 HTTP웹 기본 지식, 김영한
profile
예비 개발자의 기술 블로그 | explore, explore and explore

0개의 댓글