본문 바로가기

CS/네트워크

[HTTP] 07. 캐시 (2)

이 포스팅은 "HTTP-완벽 가이드" 책을 학습하고 정리한 것입니다.

https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=49731592

 

HTTP 완벽 가이드

HTTP 규약이 어떻게 동작하고 웹 기반 애플리케이션을 개발하는 데 어떻게 사용하는지 설명한다. 하지만 이 책은 단순히 HTTP에 대해서만 다루지는 않는다. HTTP가 효율적으로 동작하도록 함께 사

www.aladin.co.kr

 

 

 


 

 

 

7.8 사본을 신선하게 유지하기

 캐시된 사본 모두가 서버의 문서와 일치하는 것은 아니다. 캐시된 데이터는 서버의 데이터와 일치하도록 관리되어야 한다. HTTP는 어떤 캐시가 사본을 갖고 있는지 서버가 알지 못하더라도, 캐시된 데이터가 서버의 것과 일치하도록 유지할 수 있는 매커니즘을 제공한다.

 

7.8.1 문서 만료

 HTTP는 Cache-Control과 Expires라는 특별한 헤더들을 이용해서 원 서버가 각 문서에 유효기간을 붙일 수 있게 해준다. 유효기간이 지나지 않았다면, 원 서버와 통신 없이 해당 사본을 사용할 수 있다. 다만, 클라이언트가 “Cache-Control : no-cache” or “Cache-Control : max-age = 0” 과 같은 헤더를 포함할 경우, 이는 캐시된 사본이나 재점검되지 않은 리소스는 허용하지 않는 것이므로, 원 서버와 통신하여 데이터를 받아야 한다.

 

7.8.2 유효기간과 나이

 캐시된 데이터의 유효기간을 나나태기 위해 “Expires” 헤더와 “Cache-Control: max-age” 헤더를 사용할 수 있다. 두 헤더는 모두 동일한 기능을 수행하지만, 시간 계산에서 차이가 존재한다.

  • Expires 헤더 : 절대 유효시간을 명시한다. 따라서, 컴퓨터의 시간은 올바르게 맞춰져 있어야 한다.
  • Cache-Control: max-age : 문서의 최대 나이를 정의한다. 최대 나이는 문서가 처음 생성된 시점(Date 헤더에 명시된)부터, 제공하기엔 신선하지 않다고 여겨지는 시점간의 간극을 의미한다. 초단위 이다.
(1) Expires 헤더
HTTP/1.0 200 OK
Date : ~~~
Expires: Fri, 05 Jul 2002, 05:00:00 GMT

~~~

(2) Cache-Control : max-age 헤더
HTTP/1.0 200 OK
Date : ~~~
Cache-Control: max-age=484312

 (Expires에 나타나져 있는 GMT는 그리니치 표준시를 의미한다. 영국 그리니치시를 지나는 분초자오선(경도 0도)에서의 시각이다.)

 

7.8.3 서버 재검사

 캐시된 문서가 만료되었다는 것은 실제로 원 서버의 문서와 다르다는 것을 의미하지는 않는다. 다만, 이제 원 서버에 재검사를 요청해야 할 때가 되었음을 의미한다.

  • 재검사 결과 컨텐츠가 변경되었다면, 원 서버에서 해당 문서의 새로운 사본을 가져와 캐시 저장소에 저장한 뒤 클라이언트에게 응답한다.
  • 재검사 결과 컨텐츠가 변경되지 않았다면, 새 만료일을 포함한 새 헤더들만 가져와서 캐시 안의 헤더를 갱신한다.

 

7.8.4 조건부 메서드와의 재검사

 특정 조건에 부합할 때만 객체 본문을 반환해 달라는 ‘조건부 GET’요청이 존재한다. 신선도 검사와 객체를 받아오는 요청을 ‘조건부 GET’ 요청 하나에 통합해서 요청할 수 있다는 점에서 효율적이다. 이러한 요청은, GET 요청 메시지에 특별한 조건부 헤더를 추가하여 사용 가능하다.

 HTTP에서는 5가지의 조건부 헤더를 제공하는데, 헤더들은 아래와 같다.

  • If-Modified-Since : 특정 시점 이후로 문서가 변경되었다면, 서버는 객체 본문과 Last-Modified 응답 헤더를 포함한 메시지를 응답한다.
  • If-None-Match : 날짜를 변경하는 대신, 특별한 태그(ex. Etag)가 캐시의 사본과 원 서버의 리소스의 것이 일치하는 지 확인한다. 다르다면, 변경된 것이므로, 원 서버는 객체 본문을 반환한다.
  • If-Unmodified-Since : 전에 일부분 가져온 문서가 여전히 유효한지 확인할 때 사용한다.
  • If-Range : 불완전한 문서의 캐싱을 지원하기 위해 사용한다.
  • If-Match : PUT 요청을 보낼 때, 캐시에서 알고 있는 사본과 원 서버의 리소스가 일치하는 지 확인한다. 이는 동시성 제어를 위해 사용된다.

 

7.8.5 If-Modified-Since: 날짜 재검사

 If-Modified-Since 헤더를 담은 요청은 ‘IMS 요청’이라고 불리곤 한다. IMS 요청은 서버에게 리소스가 특정 날짜 이후로 변경된 경우에만 요청한 본문을 보내달라고 한다.

  • 문서가 변경되었다면, 새 문서와 새로운 만료 날짜와 그 외 다른 정보들이 담긴 헤드들과 함께 캐시에 응답된다.
  • 변경되지 않았다면, 304 Not Modified 응답 메시지가 캐시에 응답된다. 이때 원 서버는 효율을 위해 본문은 보내지 않는다.

 IMS 요청은 서버 응답 헤더인 Last-Modified 헤더와 함께 동작한다. 원 서버는 응답시 Last-Modified 헤더에 변경일자를 기입하고, 클라이언트는 추후 재검사 요청을 할때 위 Last-Modified 헤더에 기입되있던 변경일자를 IMS 헤더에 기입하여 재검사 요청을 보낸다.

 IMS가 날짜 재검사라고 해서, 원 서버가 반드시 날짜라는 형식을 기준으로 비교해야 되는 것은 아니다. 어떤 서버는 캐시가 보낸 날짜와 원 서버가 알고있는 리소스의 변경 일자가 ‘문자열 일치’인지 확인하는 방법을 사용한다. 비교 방법은 다를 수 있지만, 동일하게 변경 여부 판단이 가능하다는 점에서 동일하다.

 

7.8.6 If-None-Match : 엔터티 태그 재검사

변경 일자(날짜)를 기준으로 하는 재검사가 적절하지 않은 경우가 있다. 이 경우에는 If-None-Match 헤더를 사용해야 한다.

  • 어떤 문서가 다시 쓰여지지만(ex. 백그라운드 프로세스에 의해), 실제로 그 내용은 동일한 경우
  • 철자나 주석의 변경과 같이 사소한 변경일 경우
  • 원 서버가 리소스의 변경 일시를 정확히 판별할 수 없을 경우
  • 1초 보다 작은 간격으로 갱신되는 문서일 경우

 원 서버가 문서를 변경할 때, 해당 문서의 엔터티 태그(Etag)를 새로운 버전으로 변경할 수 있다. 반대로, 사소한 변경일 경우 Etag를 변경하지 않을 수도 있다. If-None-match 헤더의 예시는 아래와 같다.

If-None-Match: "v2.6"
If-None-Match: "v2.4","v2.5","v2.6"
If-None-Match: "foobar","A34RFAC0095"

 

7.8.7 약한 검사기와 강한 검사기

 

 위에서 언급했던, “원 서버가 문서를 변경할 때, 해당 문서의 엔터티 태그(Etag)를 새로운 버전으로 변경할 수도 있고, 안 할 수도 있다”은 이 챕터와 관련있다. 서버는 캐시된 사본을 무효화시키지 않고, 원본 문서를 살짝 고치도록 허용하는 경우가 있다. 이를 ‘약한 검사기(weak validator)’를 지원한다고 말한다.

 반대로, 원본 문서가 변경되면 반드시 엔터티 태그가 변경되도록 하는 것을, ‘강한 검사기(strong validator)’라고 말한다. 서버는 ‘W/’ 접두사로 약한 검사기를 구분한다.

 아래 이미지는 Line의 웹사이트에 대한 요청 중 일부분 이다. Etag에 기입된 값이 ‘W/’로 시작하는 것을 보아, 약한 검사기를 사용하는 것으로 유추된다.

 

 강한 엔터티 태그는 대응하는 엔터티 값이 어떻게 바뀌든 매번 반드시 같이 바뀌어야 한다. 약한 엔터티 태그는 대응하는 엔터티에 유의미한 변경이 있을 때마다 같이 변경되어야 한다.

 

7.8.8 언제 엔터티 태그를 사용하고 언제 Last-Modified 일시를 사용하는가

 HTTP/1.1 클라이언트는 서버로 부터 Etag를 반환받았다면, 반드시 엔터티 검사기(If-None-Match 헤더)를 사용해야 한다. 만약 서버가 Last-Modified만 반환했다면, 클라이언트는 If-Modified-Since 헤더를 사용하면 된다.

 만약 엔터티 태그를 활용가능한 서버라면, Last-Modified보다 엔터티 태그를 사용하는 것이 더 정확한 비교를 가능하게 하므로, 추천된다고 한다. 물론, 웹 서버의 특성과 목적마다 사용하는 태그는 달라질 수 있다.

 

Educative Answers - Trusted Answers to Developer Questions

Level up your coding skills. No more passive learning. Interactive in-browser environments keep you engaged and test your progress as you go.

www.educative.io

 서버는 클라이언트로 부터, “If-None-Match”헤더와 “If-Modified-Since”헤더를 함께 포함하는 요청을 받았다면, 각 조건부 헤더 필드의 조건이 모두 부합할 경우에만 304 Not Modified 응답을 보내야 한다.

 

7.9 캐시 제어

캐시된 문서에 대한 유효기간(만료일자)를 설정하는 헤더는 아래와 같다.

  • Cache-Control : no-store
  • Cache-Control : no-cache
  • Cache-Control : must-revalidate
  • Cache-Control : max-age
  • Expires
  • 또는, 캐시가 직접 휴리스틱 방식으로 결정하도록 함

 

7.9.1 no-cache와 no-store 응답 헤더

 

 no-cache와 no-store 헤더는 캐시가 검증되지 않은 캐시된 객체로 응답하는 것을 막는다.

  • no-store : 캐시가 그 응답의 사본을 만드는 것을 금지한다. 캐시는 no-cache 헤더가 포함된 메시지를 받고, 이를 클라이언트에게 전달한 다음, 해당 객체를 로컬 저장소에서 삭제한다.
  • no-cache : 로컬 캐시 저장소에 저장될 수는 있다. 다만, 먼저 서버와 재검사를 진행한 이후, 사용가능한 사본일 경우에만 클라이언트에게 전달할 수 있도록 한다. 이 헤더는 “재검사 없이 캐시에서 제공하지 마라”라는 문장으로 설명된다.

 

7.9.2 Max-Age 응답 헤더

(이 부분은 번역서의 오역이 존재하여 원서와 MDN 문서를 참고하였습니다.)

 

Cache-Control - HTTP | MDN

The Cache-Control HTTP header field holds directives (instructions) — in both requests and responses — that control caching in browsers and shared caches (e.g. Proxies, CDNs).

developer.mozilla.org

 원문 : The Cache-Control: max-age header indicates the number of seconds since it came from the server for which a document can be considered fresh.

 나의 번역 : Cache-Control: max-age 헤더는, 리소스가 원 서버로 부터 도착한 이후, 해당 문서가 fresh한지 판단하기 위해, 그 문서가 갖는 나이를 표현합니다.

 (즉, 문서가 도착한 순간부터 카운트 다운이 시작되며, max-age보다 카운트된 시간이 커지면, 해당 문서는 더 이상 fresh하지 않다고 판단합니다.)

 유사하게, “s-maxage”라는 헤더 필드도 존재합니다. 이 헤더는 공유된(공용) 캐시에서만 적용됩니다.

만약 서버가 max-age를 0으로 설정한다면, 해당 문서는 캐시되지 않거나, 매 요청마다 원 서버로 부터 받아야 함을 의미합니다.

 

7.9.3 Expires 응답 헤더 (← 권장안함)

더 이상 사용하지 않기를 권하는 헤더이다. 많은 서버가 동기화되지 않거나, 부정확한 시계를 갖고 있기 때문에, 만료를 절대시각 대신 경과된 시간으로 표현하는 것이 더 낫다고 판단되어, Expires 헤더는 deprecated 상태가 되었다.

Expires: Fri, 05 Jul 2002, 05:00:00 GMT

 

 하지만, 아래 이미지 처럼 MDN에서도 Expires 태그를 사용하기 때문에, 캐시 재점검을 위한 용도로는 사용하지 말라는 의미로 판단되다.

 

7.9.4 Must-Revalidate 응답 헤더

 

 만약 캐시가 만료 정보를 엄격하게 따르길 원한다면, 원 서버는 다음고 같은 Cache-Control을 붙일 수 있다.

Cache-Control: must-revalidate

 

 이 헤더는 항상 원 서버의 재검사를 수행한 이후, 클라이언트에게 캐시된 사본을 응답하도록 강제한다. “no-cache”보다는 강한 캐싱 제어이지만, “no-store”보다는 약한 캐싱 제어이다.

 

7.9.5 휴리스틱 만료

 

 만약 원 서버의 응답이 Cache-Control: max-age 헤더나 Expires 헤더 중 어느 것도 포함하지 않고 있다면, 캐시는 휴리스틱한 방식으로 문서의 유효기간을 추정한다. 유명한 알고리즘으로는 LM 인자 알고리즘이 있다. 이 알고리즘은 문서의 최근 변경일시를 알고 있을 때 사용할 수 있다. 만약, 이러한 정보도 없을 경우에는 캐시 서버에서 임의로 유효기간 설정하거나, 신선도 수명을 0으로 지정하여, 클라이언트의 요청 시 원 서버에 요청하도록 하는 방법을 사용한다.

 

7.9.6 클라이언트 신선도 제약

 클라이언트가 신선도 제약을 느슨하게 하거나 강하게 하는 방법이 존재한다. Cache-Control 요청 헤더를 사용하여 만료 제약을 엄격하게 하거나 느슨하게 한다. 방법은 아래와 같다.

  • Cache-Control: max-stale = <s> : 캐시는 신선하지 않은 문서라도 제공할 수 있으며, 만약, <s>에 값이 있을 경우, 만료시간이 그 만큼 지난 문서도 클라이언트는 받아들인다는 의미이다.
  • Cache-Control: min-fresh = <s> : 지금으로 부터 적어도 <s>초 후까지 신선한 문서만 받아들인다는 의미이다.
  • Cache-Control: max-age = <s> : 캐시는 <s>초 보다 오래된 문서는 반환할 수 없다.
  • Cache-Control: no-cache: 클라이언트는 캐시된 리소스를 재검사하기 전에는 문서를 받아들이지 않는다.
  • Cache-Control: no-store: 캐시는 저장소에서 해당 문서의 모든 흔적을 최대한 빨리 삭제해야한다. 왜냐하면, 민간한 정보를 포함할 수 있기 때문이다.
  • Cache-Control: only-if-cache: 클라이언트는 캐시된 사본만을 원한다.

'CS > 네트워크' 카테고리의 다른 글

[HTTP] 12. 기본 인증  (0) 2024.01.09
[HTTP] 10. HTTP/2.0  (2) 2024.01.08
[HTTP] 07. 캐시 (1)  (0) 2024.01.07
[HTTP] 06. 프락시  (2) 2024.01.07
[HTTP] 05. 웹 서버  (2) 2024.01.05