본문 바로가기
도서기록/HTTP 완벽가이드

7장 캐시

by 코엘리 2025. 2. 14.
반응형

7.1 불필요한 데이터 전송

  • 캐시를 이용하면 서버 응답은 캐시에 보관된다.
  • 캐시된 사본이 뒤이은 요청들에 대한 응답으로 사용되어서 트래픽을 주고받는 낭비가 줄어든다.

7.2 대역폭 병목

  • 클라이언트가 빠른 LAN에 있는 캐시로부터 사본을 가져온다면, 캐싱은 성능을 대폭 개선할 수 있다.

7.3 갑작스런 요청 쇄도(Flash Crowds)

  • 갑작스런 요청 쇄도에 대처하기 좋다.

7.4 거리로 인한 지연

  • 네트워크 라우터는 제각각 인터넷 트래픽을 지연시킨다.
  • 캐시를 근처에 설치해서 문서가 전송되는 거리를 수천 킬로에서 수십 미터로 줄일 수 있다.

7.5 적중과 부적중

  • cache hit: 캐시에 요청이 도착했을 때, 그에 대응하는 사본이 있는 경우
  • cache miss: 대응하는 사본이 없을 경우, 이 떄는 원서버에 요청을 한다.

7.5.1 재검사(Revalidation)

  • 대부분의 캐시는 '신선도 검사' 이후 오래되었을 경우 원서버에 작은 재검사 요청을 보낸다.
  • 콘텐츠가 변경되었는지 확인을 위해서는 주로 If-Modified-Since 헤더를 이용한다.

재검사 적중

  • 서버 객체가 변경되지 않았다면, 서버는 클라이언트에게 304 Not Modified 응답을 보낸다. 이는 재검사 적중 혹은 느린 적중이라고 불린다.

    재검사 부적중

  • 서버 객체가 캐시된 사본가 다르다면, 콘텐츠 전체와 함께 평범한 200 OK 응답을 보낸다.

    객체 삭제

  • 서버 객체가 삭제되었다면, 404 Not Found 응답을 놀려보낸다.

7.5.2 적중률

  • 캐시가 요청을 처리하는 비율을 캐시 적중률 혹은 문서 적중률이라고 한다.

7.5.3 바이트 적중률

  • 몇몇 큰 객체는 덜 접근되지만 크기 때문에 전체 트래픽에는 크게 기여하는 경우가 있다. 이런 이유로, 어떤 바이트 단위 적중률 측정값이 사용된다.

7.5.4 적중과 부적중의 구별

  • 클라이언트가 응답이 캐시에서 왔는지 알아내는 한 가지 방법은 Date 헤더를 이용하는 것이다. 응답의 생성일이 더 오래되었다면 클라이언트 응답은 캐시된 것임을 알 수 있다.
  • 또 다른 하나는 Age 헤더를 사용하여 응답이 얼마나 오래되었는지 알 수 있다.

7.6 캐시 토폴로지

7.6.1 개인 전용 캐시

  • 한 명에게만 할당된 개인 전용 캐시로, 한 명의 사용자가 자주 찾는 페이지를 담는다.

7.6.2 공용 캐시

  • 사용자 집단에게 자주 쓰이는 페이지를 담는다.

7.6.3 프락시 캐시 계층들

  • 작은 캐시에서 캐시 부적중이 발생했을 때, 더 큰 부모 캐시가 걸러진 트래픽을 처리하도록 하는 계층을 만드는 방식이 합리적이다.
  • 작은 캐시에는 작고 저렴한 캐시를 사용하고, 상단에는 많은 사용자들에 의해 공유되는 문서를 유지한다.

7.6.4 캐시망, 콘텐츠 라우팅, 피어링

  • 몇몇 네트워크 아키텍처는 복잡한 캐시망을 만든다.
  • 각 캐시들은 URL 에 근거하여 부모 캐시들 중 혹은 원 서버 중 하나를 동적으로 선택한다.
  • 다른 캐시들이 캐시된 콘텐츠에 부분적으로 접근할 수 있도록 허용하되, 캐시를 통한 인터넷 트랜짓(트래픽이 다른 네트워크로 옮겨가는 것)은 허용하지 않는다.

7.7 캐시 처리 단계

7.7.1 단계 1: 요청 받기

  • 들어오는 데이터를 읽는다.

    7.7.2 단계 2: 파싱

  • 요청 메시지를 파싱하여 헤더 부분을 자료 구조에 담는다.

    7.7.3 단계 3: 검색

  • 캐시는 URL을 알아내고 로컬 사본을 검사한다.
  • 로컬에서 없다면 원 서버나 부모 프락시에서 가져오거나 실패를 반환한다.

    7.7.4 단계 4: 신선도 검사

  • HTTP는 캐시가 일정 기간 동안 서버 문서의 사본을 보유할 수 있도록 해준다.
  • 신선도 한계를 넘으면 캐시는 서버와 재검서를 해야 한다.

    7.7.5 단계 5: 응답 생성

  • 캐시는 캐시된 서버 응답 헤더를 토대로 응답 헤더를 생성한다.

    7.7.6 단계 6: 전송

  • 응답 헤더가 준비되면 응답을 클라이언트에게 돌려준다.

    7.7.7 단계 7: 로깅

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

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

7.8.1 문서 만료

  • HTTP 는 Cache-Control과 Expires라는 헤더들을 이용하여 원 서버가 각 문서에 유효기간을 붙일 수 있게 해준다.
  • 문서가 만료되기 전 서버와 접촉 없이 사본을 제공할 수 있다. 단 문서가 만료되면, 서버에 재검사해야한다.

7.8.2 유효기간과 나이

  • Cache-Control:max-age 응답헤ㅔ더를 이용해서 유효기간을 명시할 수 있다.
  • Expires: 절대 유효기간을 명시한다. 만약 유효기간이 경과하면, 그 문서는 신선하지 않다.

7.8.3 서버 재검사

  • 캐시 문서가 만료되었을 때 원 서버에 검사를 요청한다.
  • 콘텐츠가 변경되었다면 캐시는 문서의 새로운 사본을 가져와 오래된 데이터 대신 저장 후 클라이언트에게 응답한다.
  • 변경되지 않았다면, 캐시는 새 만료일을 포함한 새 헤더들을 가져와서 캐시 안의 헤더들을 갱신한다.

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

  • If-Modified-Since: {date}: 만약 문서가 주어진 날짜 이후로 수정되었다면, 요청 메서드를 처리한다. 주로 캐시된 버전으로부터 콘텐츠가 변경된 경우에만 콘텐츠를 가져오기 위해 Last-Modified 서버 응답헤더와 함께 사용된다.
  • If-None-Match: {tags}: 캐시된 태그가 서버에 있는 문서의 태그와 다를때만 요청한다.

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

  • 흔히 IMS 요청으로 불리는데, 리소스가 특정 날짜 이후 변경된 경우 요청한 본문을 보내달라고 한다.

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

  • 어떤 문서들은 일정 시간 간격으로 다시 쓰여지지만 실제로는 같은 데이터를 포함하는 경우도 있다. 이러한 경우들을 피하고 문서가 변경했을 때만을 판단하기 위해 엔터티 태그를 새로운 버전으로 표현할 수 있다.

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

  • 서버가 때로 캐시된 사본을 무효화시키지 않고 문서가 같다고 주장할 수 있도록 '약한 검사기'를 지원한다.
  • 강한 검사기는 콘텐츠가 바뀔 때마다 캐시가 바뀐다.
  • 원 서버는 서로 다른 두 엔터티에 대해 강한 엔터티 태그 값을 재활용해서는 안되며, 약한 엔터티 태그 값이라고 할지라도 서로 의미가 다른 두 엔터티에 대해서는 재활용해서는 안된다.

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

  • 서버가 엔터티 태그를 반환하면, 엔터티 태그 검사기를 사용해야 한다.
  • 서버가 Last-Modified 값만을 반환하면, 클라이언트는 If-Modified-Since 검사를 사용할 수 있다.
  • 둘 다 사용이 가능하면 두 가지 재검사 정책을 모두 사용해야 한다.

7.9 캐시 제어

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

  • no-store: 캐시가 응답 사본을 만드는 것을 금지한다.
  • no-cache: 로컬 캐시 저장소에 저장될 수 있다. 다만, 서버와 재검사를 하지 않고서는 제공될 수 없다.

7.9.2 Max-Age 응답 헤더

  • Cache-Control: max-age는 신선하다고 간주되었던 문서가 서버로부터 온 이후로 흐른 시간이고, 초로 나타낸다.
  • 서버는 이 값을 0으로 설정하여 매 접근마다 캐시 하지 않거나 리프레시 하도록 요청할 수 있다.

7.9.3 Expires 응답 헤더(Deprecated)

  • 초 단위의 시간 대신 실제 만료 날짜를 명시한다.
  • 단, 많은 서버가 부정확한 시계를 갖고 있기 때문에, 만료를 절대 시각 대신 경과된 시각으로 표현하는 것이 낫다고 판단했다.

7.9.4 Must-Revalidate 응답 헤더

  • Cache-Control:must-revalidate 응답 헤더는 이 객체의 신선하지 않은 사본을 원 서버와의 최초의 재검사 없이는 제공해서는 안 됨을 의미한다.

7.9.5 휴리스틱 만료

  • 응답이 Cache-Control: max-age 헤더나 Expires 헤더 중 어느 것도 포함하지 않다면 캐시는 경험적인 방법으로 최대 나이를 계산한다.
  • 이 때 문서의 최근 변경일시를 사용하는 LM 인자 알고리즘을 사용한다. 이는 캐시가 서버와 대화했을 때와 서버로 부터 얻은 문서의 최근 변경 일시의 시간차를 계산하고, 이 차의 일부분을 캐시의 신선도 지속기간으로 사용한다.
$마지막_수정_이후로_경과한_시간 = max(0, $서버의_Date - $서버의_Last_Modified);
$서버_신선도_한계 = int($마지막_수정_이후로_경과한_시간 * $lm_인자);

7.10 캐시 제어 설정

7.10.1 아파치로 HTTP 헤더 제어

mod_headers

  • 개별 헤더를 설정할 수 있는 지시어를 이용해 아파치 설정 파일에 추가할 수 있다.

    mod_expires

  • 적절한 만료 날짜가 담긴 Expires 헤더를 자동으로 생성하는 프로그램 로직을 제공한다.

    mod_cern_meta

  • 제어하고자 하는 파일에 대응되는 메타 파일을 생성해주고, 각 메타파일에 원하는 헤더를 추가할 수 있다.

7.10.2 HTTP-EQUIV

  • HTTP 서버 응답 헤더는 문서의 만료와 캐시 제어 정보를 돌려주기 위해 사용된다.
  • 웹 서버 설정 파일과 상호작용 없이 쉽게 HTML 문서에 HTTP 헤더 정보를 부여할 수 있도록 하기 위해, HTML 2.0은 'META HTTP-EQUIV' 태그를 정의했다.
  • 이 기능은 서버의 부하를 가중시키고, 설정값이 정적이고, HTML 을 제외한 다른 파일의 파일은 지원하지 않아서 잘 사용하지 않는다.

7.11 자세한 알고리즘

7.11.1 나이와 신선도 수명

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

7.11.2 나이 계산

$응답_지연_추정값 = ($응답을_받은_시각 - $요청을_보낸_시간);
$문서가_캐시_도착했을때_나이 = $보정된_겉보기_나이(서버) + $응답_지연_추정값;
$사본_캐시_머무른_시간 = $현재_시간 - $응답_받은_시각;
$나이 = $문서가_캐시_도착했을때_나이 + $사본_캐시_머무른_시간;

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

$겉보기_나이 = max(0, $응답_받은_시각 - $Date_헤더값);
$문서가_캐시_도착했을때_나이 = $겉보기_나이;
  • Date 헤더는 원 서버 날짜를 서술한다. 만약, 두 컴퓨터 시계 설정 차이로(클록 스큐) 겉보기 나이가 부정확하거나 음수가 되는 경우를 대비하여 max 값을 비교한다.

점층적 나이 계산

  • 클록 스큐에 초래하는 정확도 손실에 대해서 문서가 프락시나 캐시를 통과할 때마다 Age 헤더에 상대적인 나이를 누적해서 더하도록 한다.
  • Age 헤더를 이용하여 자신의 내부 시계를 이용해 체류 시간을 계산할 수 있다.
$겉보기_나이 = max(0, $응답_받은_시각 - $Date_헤더값);
$보정된_겉보기_나이 = max($겉보기_나이, $Age_헤더값);
$문서가_캐시_도착했을때_나이 = $보정된_겉보기_나이

네트워크 지연에 대한 보상

  • Date 헤더는 문서가 원서버를 언제 떠났는지는 알려주지만, 캐시로 옮겨가는 과정에서 얼마나 시간을 소비했는지 알려주지 않는다.
  • 캐시는 언제 문서를 요청했고 언제 도착했는지 알고 있다. 이를 이용하여 전체 왕복 시간을 더함으로써 네트워크 지연을 보수적으로 교정한다.
$겉보기_나이 = max(0, $응답_받은_시각 - $Date_헤더값);
$보정된_겉보기_나이 = max($겉보기_나이, $Age_헤더값);
$응답_지연_추정값 = ($응답을_받은_시각 - $요청을_보낸_시간);
$문서가_캐시_도착했을때_나이 = $보정된_겉보기_나이 + $응답_지연_추정값;

7.11.3 완전한 나이 계산 알고리즘

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

7.12 캐시와 광고

7.12.1 광고 회사의 딜레마

  • 사용자가 광고를 볼 때마다 돈을 버는데, 캐시가 원 서버 접근을 모두 흡수해버리는 경우 문제가 생긴다.

7.12.2 퍼블리셔의 응답

  • 오늘날 광고회사들은 광고 시청 수를 가로채지 못하도록 '캐시 무력화' 기법을 사용하는데, 이는 캐싱의 긍정적인 효과를 감소시킨다.
  • 이상적으로는 캐시가 트래픽을 흡수하게 하고, 캐시는 원서버에게 적중이 얼마나 많이 일어났는지 알려주어야 한다.

7.12.3 로그 마이그레이션

  • 캐시는 적중 로그를 유지하다가 이 로그를 서버에게 나누어 줄 수 있다.
  • 하지만 적중 로그는 크기가 커서 옮기기 어렵다.
  • 뿐만 아니라, 인증과 프라이버시 이슈도 있다.

7.12.4 적중 측정과 사용량 제한

  • RFC 2227, "HTTP를 위한 간단한 캐시 적중량 측정과 사용량 제한" 이 프로토콜은 HTTP에 특정 URL에 대한 캐시 적중 횟수를 정기적으로 서버에게 돌려주는 Meter 라는 새 헤더를 추가한다.
  • 이 방법은 서버가 캐시된 문서가 적중한 횟수의 정기적 업데이트를 캐시로부터 받는다.
반응형

'도서기록 > HTTP 완벽가이드' 카테고리의 다른 글

9장 웹 로봇  (0) 2025.03.27
8장 통합점: 게이트웨이, 터널, 릴레이  (0) 2025.03.13
6장 프락시  (0) 2025.01.24
5장 웹 서버  (1) 2025.01.17
4장 커넥션 관리  (0) 2024.12.20