본문 바로가기
cs/컴퓨터 네트워크

HTTP 캐시와 조건부 요청, 프록시 캐시

by 장인이 2023. 1. 13.

0. 개요

 이번 게시물에서는 HTTP 캐시와 조건부 요청, 프록시 캐시에 대해 작성할 것이다. 해당 게시물을 보기 전, 아래 링크의 글을 보고 오는 것을 추천한다.

(HTTP란?)

 

 

1. 캐시를 사용하지 않을 경우

 우선 캐시가 무엇인지, 그리고 왜 사용되는지를 알기 위해서 우선 캐시를 사용하지 않을 경우 어떻게 되는지에 대해 알아보자.

 

- 첫번째 요청

 서버에서 star.jpg라는 이미지를 받기 위해 요청하고, 해당 이미지가 담긴 HTTP 메시지를 응답받는다.

 

- 두번째 요청

 한번 더 같은 이미지 요청을 하면, 다시 해당 이미지가 담긴 HTTP 메시지를 응답받는다.

 

- 이렇게 데이터가 변경되지 않아도, 클라이언트는 네트워크를 통해서 데이터를 다운로드 받아야한다.

  -> 인터넷 네트워크는 느리고 비싸며, 브라우저의 로딩 속도도 느리다.

  -> 따라서, 느린 사용자 경험을 주게 될 것

 

 

2. 캐시 적용

- 첫 번째 요청

- 캐시 적용 전과 다르게, 응답에서 cache-control: max-age=60 이라는 값을 보내주었다.

- 웹 브라우저에서는 응답을 받은 후, 브라우저 캐시에 해당 이미지를 저장한다.

  -> 헤더에 명시된 값에 따라 이 캐시는 60초간 유효해진다.

 

- 두 번째 요청

- 두 번째 요청시 우선 브라우저 캐시를 확인한다.

  -> 유효기간이 지나지 않았으므로, 캐시에서 이미지를 가지고 온다.

 

- 따라서 네트워크를 사용하지 않아도 되며, 브라우저 로딩 속도가 매우 빨라진다.

  -> 빠른 사용자 경험

 

- 세 번째 요청

- 브라우저 캐시를 확인 후 유효기간이 지남을 확인한다.

  -> 다시 첫번째 요청처럼 서버에 요청, 서버에서도 다시 응답을 내려준다.

  -> 이때 다시 네트워크 다운로드가 발생한다.

 

 그런데 위 경우도 결국 같은 star.jpg를 다시 네트워크에서 다운로드 받는 것이다(변경되지 않았다는 가정 하에). 데이터가 변경되지 않았어도 같은 응답을 가져오기 때문에, 조금 비효율적인것 같다...

 

 

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

 캐시 유효시간이 초과해서 서버에 다시 요청할 경우, 다음 두가지 상황이 나타난다.

 

1. 서버에서 기존 데이터를 변경한 경우

2. 서버에서 기존 데이터를 변경하지 않은 경우

 

만일에 데이터가 변경되지 않았다면?

-> 데이터를 다시 전송하는 대신에, 캐시 유효시간이 초과했더라도 저장해둔 캐시를 재사용하면 된다!

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

 

1) Last-Modified, If-Modified-Since

- 첫 번째 요청

- 서버에서 Last-Modified: 2020년 11월 10일 10:00:00 이라는 HTTP 헤더를 추가해서 응답하였다.

- 브라우저 캐시에 해당 정보를 추가해서 저장한다.

 

- 두 번째 요청

- 브라우저 캐시를 확인한 후 유효기간이 만료되었다면, 서버에 다시 요청을 보낸다.

- 이때, if-modified-since: 2020년 11월 10일 10:00:00 이라는 HTTP 헤더를 추가해서 서버에 요청한다.

 

- 서버는 요청을 받은 후, 서버가 지니고 있는 데이터와 데이터 최종 수정일을 비교한다.

  -> 데이터가 아직 수정되지 않았다면?

 

- 서버에서는 304 Not Modified 리다이렉트 상태코드와 함께 응답해준다.

(304 상태코드: 리소스가 수정되지 않았으며, 저장된 캐시를 재사용하라는 메시지)

  -> 이때 HTTP Body 없이 응답해, 네트워크 다운로드를 절약할 수 있다!!!

- 웹 브라우저는 응답을 받은 후, 캐시의 유효기간을 갱신한다.

 

- 그 후, 캐시에서 기존 이미지를 조회한다.

 

 정리해보면 캐시의 유효 시간이 초과해도, 서버의 데이터가 갱신되지 않았다면 304 Not Modified + 헤더 메타 정보만 응답한다. 클라이언트는 서버가 보낸 헤더 정보로 캐시를 갱신하고, 캐시에 저장되어 있는 데이터를 재활용한다.

-> 결과적으로 용량이 적은 헤더 정보만 다운로드 하는 실용적인 해결책이다.

 

- 단점

- 저장하는 단위가 초 단위이므로, 1초 미만 단위로 캐시 조정이 불가능하다.

- 날짜 기반의 로직을 사용한다.

  -> 데이터를 수정해서 최종 수정일이 달라지지만, 같은 데이터를 수정해서 데이터의 결과가 같다면?

  -> 결국 같은 데이터를 다시 다운받을 것이다.

- 서버에서 별도의 캐시 로직을 관리하고 싶을 경우, 관리할 수 없다.

  -> ex) 공백, 주석처럼 영향이 없는 변경은 캐시를 유지하고 싶다!

 

2) ETag, If-None-Match

- Etag(Entity Tag)라는 방식도 존재한다. 이는 캐시용 데이터에 임의의 고유한 버전 이름을 달아둔다.

ex) ETag: "v2.0", ETag: "sadf123"

 

- 따라서 데이터가 변경되면 이 이름을 바꾸는 것이다!

ex) ETag: "aaaa" -> ETag: "bbbb"

 

- 단순하게 ETag를 보내서 같다면 유지시키고, 다르면 다시 응답받으면 된다!

 

- 첫 번째 요청

- 서버에서 ETag: "aaaaaaaaaa" 이라는 HTTP 헤더를 추가해서 응답한다.

- 브라우저 캐시에 해당 정보를 추가해서 저장한다.

 

- 두 번째 요청

- 브라우저 캐시를 확인한 후 유효기간이 만료되었다면, 서버에 다시 요청을 보낸다.

- 이때, If-None-Match: "aaaaaaaaaa" 이라는 HTTP 헤더를 추가해서 서버에 요청한다.

 

- 서버는 요청을 받은 후, 서버가 지니고 있는 데이터와 ETage를 비교한다.

  -> 데이터가 아직 수정되지 않았다면?

 

- 서버에서는 304 Not Modified 리다이렉트 상태코드와 함께 응답해준다.

(304 상태코드: 리소스가 수정되지 않았으며, 저장된 캐시를 재사용하라는 메시지)

  -> 이때 HTTP Body 없이 응답해, 네트워크 다운로드를 절약할 수 있다!!!

- 웹 브라우저는 응답을 받은 후, 캐시의 유효기간을 갱신한다.

 

 결국, 이는 캐시 제어 로직을 서버에서 완전히 관리하는 방식이다. 또한, 클라이언트는 단순히 ETag 값을 서버에 제공만 하며, 캐시 메커니증을 모르게 된다.

 

 

3. 캐시 제어 헤더

 이 외에 위의 예시에서 기본적으로 사용하고 있던 캐시 제어 헤더에 대해 알아보자.

 

Cache-Control

- 캐시를 제어하는 헤더이다.

- max-age, no-cache, no-store 값을 지닐 수 있다.

  - max-age

   -> 캐시 유효 시간을 나타내며, 초 단위이다.

  - no-cache

   -> 데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증하고 사용하라는 뜻이다.

   (origin 서버에 대한 내용은 게시물 아래쪽에 설명)

  - no-store

   -> 데이터에 민감한 정보가 있으므로 저장하면 안된다.

   -> 즉, 메모리에서 사용하고 최대한 빨리 삭제하라는 뜻

- max-age는 위에서 많이 다루어보았고, no-cache, no-store는 아래 5번에서 다뤄볼 예정이다.

 

Pragma

- 마찬가지로 캐시를 제어하는 헤더이지만, HTTP 1.0의 하위 호환이다.

- 하지만 예전 브라우저를 사용하는 경우를 대비하여 넣기도 한다.

 

Expires

캐시 만료일을 지정하는 헤더이다.

- 마찬가지로 Cache-Control의 하위 호환이다. (덜 유연하기 때문)

- Cache-Control: max-age과 함께 사용하면, Expires는 무시된다.

ex) expires: Mon, 01 Jan 1990 00:00:00 GMT

 

 

4. 프록시 캐시

- 만일에 클라이언트와 원 서버간의 거리가 너무 길다면?

  -> 간단한 네트워크 통신도 많은 시간이 소요될 것이다.

 

- 따라서 중간에 프록시 캐시 서버를 도입한다.

 -> 이로 인해 더 효율적인 네트워크 통신이 가능하도록 한다.

- 웹 브라우저가 저장해야 하는 캐시 private 캐시라고 한다.(기본값)

- 프록시 캐시에 저장되어도 되는 캐시public 캐시라고 한다.

 

Cache-Control

- 프록시 캐시와 관련된 내용들이 있다.

- public

  -> 응답이 public 캐시에 저장되어도 된다.

- private

  -> 응답이 해당 사용자만을 위한 것이며, private 캐시에 저장해야 한다.(기본값)

- s-maxage

  -> 프록시 캐시에만 적용되는 max-age라고 생각하자.

 

Age: 60

- HTTP 헤더이다.

- 오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간을 말한다.

- 단위는 초이다.

 

 

5. 캐시 무효화

위에서 잠깐 언급했던 Cache-Control: no-cache, no-store, 그리고 추가로 must-revalidate 내용에 대해 알아보자.

 

Cache-Control: no-store

- 데이터에 민감한 정보가 있으므로, 저장하면 안된다.

- 메모리에서 사용하고, 최대한 빨리 삭제하라는 뜻

 

Cache-Control: no-cache

- 데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증한 후, 사용해라

 

Cache-Control: must-revalidate

- 캐시 만료 후 최초 조회시, 원 서버에 무조건 검증해야 한다.

  -> 원 서버 접근 실패시 반드시 오류가 발생해야 한다.(504 Gateway Timeout)

- must-revalidate는 캐시 유효기간이라면 캐시를 사용한다.

 

Pragma: no-cache

- 위에서도 언급했지만, HTTP 1.0의 하위 호환이다.

 

no-cachemust-revalidate 두 내용이 비슷해 보이지만, 약간 다른 특징들을 지니고 있다. 두 내용의 차이점을 살펴보자.

 

1) no-cache

- 기본 동작

1. 웹 브라우저에서 no-cache와 함께 캐시를 서버에 요청한다.

2. no-cache가 붙어있으므로, 프록시 캐시 서버에서 다시 원 서버에 요청한다.

3. 원 서버에서 내용을 검증 후, 304를 응답한다.

4. 프록시 캐시 서버에서 다시 웹 브라우저에게 응답한다.

5. 웹 브라우저에 있는 캐시 데이터를 다시 사용한다.

 

- 프록시 캐시 서버가 원 서버에 접근을 못한다면?

- 어떤 이슈로 인하여 프록시 캐시 서버와 원 서버가 서로 통신이 안될 수 있다.

- 그러면, 프록시 캐시 서버의 설정에 따라 응답이 달라진다.

  -> 에러가 나는 것 보다는 예전 데이터라도 보여주고 싶다면? -> 200 OK 반환

  -> 혹은 에러를 보낼 수도 있다.

  

2) must-revalidate

- 기본 동작

- 기본 동작은 no-cache와 동일하다.

 

- 프록시 캐시 서버가 원 서버에 접근을 못한다면?

- 프록시 캐시 서버와 원 서버가 서로 통신이 안된다고 해보자.

- 그럼 무조건 504 Gateway Timout을 응답한다.

 


위 내용은 김영한 님의 인프런 강의 "모든 개발자를 위한 HTTP 웹 기본 지식"의 내용과 강의자료를 토대로 작성된 게시글입니다.

강의 링크:

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8

'cs > 컴퓨터 네트워크' 카테고리의 다른 글

OSI 7계층, TCP/IP 5계층  (0) 2023.11.09
HTTP 쿠키  (0) 2023.01.13
HTTP 헤더  (0) 2023.01.13
HTTP 상태코드  (0) 2023.01.12
HTTP API 설계하는 법  (0) 2023.01.12

댓글