운영체제를 공부하다보면 CPU와 메모리 사이에 캐시가 중요한 역할을 한다는 사실을 확인할 수 있는데, http강의에서도 캐시 관련 헤더에 대해 소개되어 반가운(?) 마음이 들었다.
만약 캐시가 없다면, 클라이언트가 서버에 요청하는 데이터가 동일한 내용이라고 해도 계속 새로 다운로드 받아야 한다. 네트워크 속도가 느려지면 브라우저 로딩 속도도 느려지고, 이는 당연히 사용자의 느린 경험으로 연결된다.
그래서 서버가 cache-control: max-age= 60
를 포함해서 응답하면, 클라이언트는 데이터를 캐시에 넣고 사용할 수 있다. 그러면 유효 시간(60초) 동안에는 서버로 갈 필요 없이 캐시에서 바로 꺼내 쓰면 되는 것이다.
캐시를 사용하면...
- 캐시 가능 시간 동안 네트워크를 사용할 필요 없다 (네트워크 사용량 down)
- 브라우저로딩 속도가 빨라진다 -> 빠른 사용자 경험
📍 1 차로 cache를 잘 썼다 치자. 그런데 그 이후에는?
그럼 만약 유효 시간 60초가 지나고 서버에 다시 데이터를 요청하면 어떻게 될까? 서버는 기존 데이터를 변경하지 않는다. 어느 쪽이든 서버는 또 동일하게
cache-control: max-age= 60
을 포함해서 응답할 것이고, 클라이언트는 다시 데이터를 60초 동안 유효한 상태로 캐시에 저장한다. 결국 네트워크 다운로드가 반복되는 것이다.
(위의 max-age:60
은 예시다)
이를 해결하기 위해 검증 헤더를 사용한다. 2가지 방법이 있다.
- if-modified-since/if-unmodified-since, last-modified
- if-match/if-non-match, ETag
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(아무 내용 없음))
: 클라이언트는 캐시를 재세팅하고 데이터를 꺼내서 사용한다
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(아무 내용 없음))
그뿐 아니라, 데이터 최종 날짜는 최종 결과와 관계 없이 건드린 흔적만 생겨도 갱신된다. 그러면 당연히 서버는 다른 데이터로 받아들이고 클라이언트 캐시로 리다이렉트해주지 못한다.
📍 캐시 제어 관련 헤더를 정리해보자
간혹 웹브라우저가 데이터 보고 임의로 캐시에 저장하는 경우가 있기 때문에, 캐시 제어는 중요하다.
<조건부 헤더>
<검증 헤더>
📍 프록시 캐시
웹브라우저에서 데이터를 서버에 요청할 때, 매번 origin server(원 소스가 있는 서버, 원 서버로 불림)에 접근하려면 시간이 오래 걸린다. 그래서 중간에 프록시 서버를 두고, DNS 등을 조정해서 웹브라우저의 요청이 프록시 서버로 가게 만드는 것이다.
이 때 프록시 서버의 캐시는 public 캐시, 웹브라우저 캐시는 private 캐시라고 한다.
예를 들어, youtube에서 사람들이 잘 안보는 동영상은 로딩 속도가 느린 반면, 조회수가 높은 동영상은 로딩 속도가 빠르다. 이는 해당 동영상이 프록시 서버를 통해 전달되기 때문이다.
클라이언트가 임의로 private 캐시를 사용하는 걸 막기 위해서 캐시 제어(캐시 무효화)는 반드시 필요한데, 보통 아래 헤더들을 추가하면 제어가 잘 된다.
cache-control: no-cache, no-store, must-revalidate
pragma: no-cache
추가로 넣을 수 있는 제어 헤더는 아래와 같다.
*제어 헤더 중, no-cache와 must-revalidate의 차이는?
순간적인 네트워크 단절로 인해 원 서버에 접근하기 어려운 경우, cache-control:no-cache
는 프록시 서버에서 처리할 수 있다. 과거 데이터라도 전달해야 하는 경우가 있으므로.
반면 cache-control:must-revalidate
는 원 서버의 검증을 무조건 받아야 하기 때문에 504 gateway timeout 이라는 오류를 보낸다.