✊ 필오의 개발일지
Back to Posts
2019년 10월 5일

캐시의 원리와 제어방법

캐시의 원리와 제어방법

캐시의 원리와 제어방법을 알아본다. 클라가 요청 메시지를 받은 이후의 처리단계를 기준으로 캐시는 어떤 원리로 사본을 관리하는지, 단계별로 어떤 제어가 가능한지를 알아보려고 한다.

7. 캐시 처리 단계

처리단계는 7단계로 이루어져 있다.

단계1: 요청받기

네트워크 커넥션에서의 활동을 감지하고, 들어오는 데이터를 읽어들인다.

단계2: 파싱

요청 메세지를 여러 부분으로 파싱하여 헤더 부분을 조작하기 쉬운 자료 구조에 담는다.

캐싱 소프트웨어가 헤더 필드를 처리하고 조작하기 쉽게 만들어 준다.

단계3: 검색

URL을 알아내고 그에 해당하는 로컬 사본이 있는지 검사한다.

단계4: 신선도 검사

HTTP는 캐시가 일정 기간 동안 서버 문서의 사본을 보유할 수 있도록 해준다.

신선도 검사 알고리즘은 아래에.

단계5: 응답 생성

캐시 된 응답을 원서버에서 온 것처럼 보이게 하고 싶기 때문에 캐시는 캐시 된 서버 응답 헤더를 토대로 응답 헤더를 생성한다.

캐시는 클라에 맞게 이 헤더를 조정해야 하는 책임이 있다.

단계6: 전송

단계7: 로깅

대부분의 캐시는 로그 파일과 캐시 사용 통계를 유지한다.

캐시 로그 포맷

많은 캐시 제품이 커스텀 로그 파일을 허용한다.

전체 Flow



8. 사본을 신선하게 유지하기

HTTP는 어떤 캐시가 사본을 갖고 있는지 서버가 기억하지 않더라도, 캐시 된 사본이 서버와 충분히 일치하도록 유지할 수 있게 해주는 매커니즘을 갖고 있다. 매커니즘은 문서 만료서버 재검사라고 부른다.

8.1 문서만료

HTTP는 Cache-ControlExpires라는 헤더들을 이용하여 원서버가 각 문서에 유효기간을 붙일 수 있게 해준다.

유효기간과 나이

ExpiresCache-Control:max-age 헤더는 기본적으로 같은 일을 하지만, 절대 시간은 컴퓨터의 시계가 올바르게 맞추어져 있을 것을 요구한다.

Cache-Control:max-age

Expires

절대 유효기간을 명시한다. 만약 유효기간이 경과했다면, 그 문서는 더 이상 신선하지 않다.

8.2 서버 재검사 reValidation

캐시는 문서의 신선도를 매 요청마다 검증할 필요가 없다.

HTTP 프로토콜은 캐시가 다음 중 하나를 반환할 것을 요구한다.

조건부 메서드와 재검사

HTTP의 조건부 메서드는 재검사를 효율적으로 만들어준다. HTTP는 캐시가 서버에게 조건부 GET이라는 요청을 보낼 수 있도록 해준다.

1. If-Modified-Since: 날짜 재검사

If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT

If-Modified-Since 헤더는 Last-Modified 헤더와 함께 동작한다.

If-Modified-Since: <캐시 된 마지막 수정일>

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

서버는 무서에 대한 일련번호와 같이 동작하는 특별한 태그를 제공할 수 있다.(ETag) 캐시 된 태그가 서버에 있는 문서의 태그와 다를 때만 요청을 처리한다.

최근 변경일시 재검사가 행해지기 어려운 상황이 있다.

  1. 일정 시간 간격으로 다시 쓰여지지만, 같은 데이터를 포함한다. (내용변화가 없음)
  2. 어떤 문서들의 변경은 다시 읽어들이기엔 사소한 것 (철자나 주석)
  3. 어떤 서버들은 그들이 갖고 있는 페이지에 대한 최근 변경 일시를 정확하게 판별할 수 없다.
  4. 1초보다 작은 간격으로 갱신되는 문서를 제공하는 서버들에게는, 변경일에 대한 1초의 정밀도는 충분하지 않을 수 있다.
조건부 요청 GET /index.html HTTP/1.0 If-None-Match: "v2.6"
응답 HTTP/1.0 304 Not Modified Date: Wed, 03 Jul 2002, 19:18:23 GMT ETag: "v2.6" Expires: Fri, 05 Jul 2002, 05:00:00 GMT

약한 검사기와 강한 검사기

강한 검사기는 콘텐츠가 바뀔 때마다 바뀐다. 약한 검사기는 어느 정도 콘텐츠 변경을 허용하지만, 콘텐츠의 중요한 의미가 변경되면 함께 변경된다.

ETag: W/"v2.6" If-None-Match: W/"v2.6"

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



9. 캐시 제어

아래는 HTTP는 문서가 얼마나 오랫동안 캐시될 수 있게 할 것인지, 서버가 설정할 수 있는 여러 가지 방법이다.

  1. Cache-control: no-cache
  2. Cache-control: no-store
  3. Cache-control: must-revalidate
  4. Cache-Control: max-age=<seconds>
  5. Cache-control: s-maxage=<seconds>
  6. Expires 날짜 헤더를 응답에 첨부할 수 있다.
  7. 아무 만료 정보도 주지 않고, 캐시가 스스로 체험적인(휴리스틱 heuristic) 방법으로 결정하게 할 수 있다.

9.1 no-cahce와 no-store 응답 헤더

캐시가 검증되지 않은 캐시 된 객체로 응답하는 것을 막는다.

  1. Cache-control: no-store: 캐시가 그 응답의 사본을 만드는 것을 금지한다.
  2. Cache-control: no-cache: 로컬 캐시 저장소에 저장될 수 있다. 다만, 먼저 서버와 재검사를 하지 않고서는 캐시에서 클라로 제공될 수 없을 뿐이다.

    Do Not Serve From Cache Without Revalidation (재검사 없이 캐시에서 제공하지 마라)

  3. Pragma: no-cache: HTTP/1.0+ 하위 호환성을 위해 HTTP/1.1에 포함되어있다. 웬만하면 Cache-control: no-store

9.2 Max-Age 응답 헤더

9.3 Expires 응답헤더

9.4 Must-Revalidate 응답 헤더

9.5 휴리스틱 만료

LM(last-modified) 인자 알고리즘 (휴리스틱 만료 알고리즘)

  1. 캐시 된 문서가 마지막으로 변경된 것이 엄청 예전이라면, => 안정적인 문서일 것이다 => 갑자기 바뀔 일을 크지 않을 것이고 => 캐시에 더 오래 보관하고 있어도 안전하다.
  2. 캐시 된 문서가 최근 변경되었다면 => 자주 변경될 것이고, => 서버와 재검사하기 전까지 짧은 기간 동안만 캐시해야 한다.
$마지막_수정이후로_경과한_시간 = max(0, $서버의_Date - $서버의_Last_Modified) $서버_신선도_한계 = int($마지막_수정_이후로_경과한_시간 * $lm_인자)

9.6 클라 신선도 제약

클라는 Cache-control 요청 헤더를 사용하여 만료 제약을 엄격하게 하거나, 느슨하게 할 수 있다.

  1. Cache-Control: max-stale[=<seconds>]: 클라이언트가 캐시의 만료 시간을 초과한 응답을 받아들일지를 나타낸다. 초가 지정되면, 클라는 만료시간이 그 매개변수 값만큼 지난 문서도 받아들인다.
  2. Cache-Control: min-fresh=<seconds>: 클라는 지금으로부터 s초 후까지 신선한 문서만을 받아들인다.
  3. Cache-Control: max-age=<seconds>: s초보다 오랫동안 캐시 된 문서를 반환할 수 없다.
  4. Cache-control: no-cache: 캐시 된 리소스는 재검사하기 전에는 받아들이지 않을 것이다.
  5. Cache-control: no-store: 저장소에서 문서의 흔적을 빨리 삭제해야 한다. 문서에는 민감한 정보가 포함되어 있기 때문
  6. Cache-control: only-if-cached: 클라는 캐시에 들어있는 사본만을 원한다.


10. 자세한 알고리즘

나이와 신선도 수명

$충분히_신선한가 = $나이 < $신선도_수명

10.1 나이 계산

$겉보기_나이 = max(0, $응답을_받은_시각 - $Date_헤더값) $보정된_겉보이_나이 = max($겉보기_나이, $Age_헤더값) $응답_지연_추정값 = $응답을_받은_시각 - $요청을_보낸_시각; $문서가_우리의_캐시에_도착했을_때의_나이 = $보정된_겉보기_나이 + $응답_지연_추정값; $사본이_우리의_캐시에_머무른_시간 = $현재_시각 - $응답을_받은_시각; $나이 = $문서가_우리의_캐시에_도착했을_때의_나이 + $사본이_우리의_캐시에_머무른_시간;

1. 겉보기 나이는 Date 헤더에 기반한다.

$겉보기_나이 = $응답을_받은_시각 - $Date_헤더값
$겉보기_나이 = max(0, $응답을_받은_시각 - $Date_헤더값)

2. 점층적 나이 계산 (Age 헤더)

Age 헤더 값은 문서가 프락시들을 통과하면서 점점 늘어난다.

상대 나이값은 가장 큰 것(보수적)이 선택된다.

$겉보기_나이 = max(0, $응답을_받은_시각 - $Date_헤더값) $보정된_겉보이_나이 = max($겉보기_나이, $Age_헤더값) $문서가_우리의_캐시에_도착했을_때의_나이 = $보정된_겉보기_나이

3. 네트워크 지연에 대한 보상

$겉보기_나이 = max(0, $응답을_받은_시각 - $Date_헤더값) $보정된_겉보이_나이 = max($겉보기_나이, $Age_헤더값) $응답_지연_추정값 = $응답을_받은_시각 - $요청을_보낸_시각; $문서가_우리의_캐시에_도착했을_때의_나이 = $보정된_겉보기_나이 + $응답_지연_추정값;

4. 캐시에 저장되면, 나이를 더 먹는다.

$나이 = $문서가_우리의_캐시에_도착했을_때의_나이 + $사본이_우리의_캐시에_머무른_시간;

10.2 신선도 수명 계산

sub 서버_신선도_한계 { local($휴리스틱, $서버_신선도_한계, $마지막으로_변경된_시각) $휴리스틱 = 0; if ($Max_Age_값이_설정되었나) { $서버_신선도_한계 = $Max_Age_값 } elsif ($Expires_값이설정되었나) { $서버_신선도_한계 = $Expires_값 - $Date_값 } elsif ($Last_Modified_값이_설정되었나) { $마지막으로_변경된_시각 = max(0, $Date_값 - $Last_Modified_값) $서버_신선도_한계 = int($마지막으로_변경된_시각 * $lm_인자); $휴리스틱 = 1; } else { $서버_신선도_한계 = $캐시_최소_수명_기본값; $휴리스틱 = 1; } if ($휴리스틱) { if ($서버_신선도_한계 > $캐시_최대_수명_기본값) $서버_신선도_한계 = $캐시_최대_수명_기본값 if ($서버_신선도_한계 < $캐시_최소_수명_기본값) $서버_신선도_한계 = $캐시_최소_수명_기본값 } return $서버_신선도_한계 } sub 클라이언트가_수정한_신선도_한계 { $나이_한계 = 서버_신선도_한계() if ($Max_Stale_값이_설정되었나) { if ($Max_Stale_값 == $INT_MAX) { $나이_한계 = $INT_MAX } else { $나이_한계 = 서버_신선도_한계() + $Max_Stale_값 } } if ($Min_Fresh_값이_설정되었나) { $나이_한계 = min($나이_한계, 서버_신선도_한계() - $Min_Fresh_값) } if ($Max_Age_값이_설정되었나) { $나이_한계 = min($나이_한계, $Max_Age_값) } }

전체 과정은 문서의 나이신선도 한계라는 두 가지 변수가 관련되어 있다.



참고자료

PreviousWIP_웹 로봇
Next캐시의 개념과 장점

Related

© 2025 Felix