개발도서 읽기/HTTP 완벽 가이드

[2. HTTP 아키텍처] 7장) 캐시

까연 2021. 5. 2. 13:53

캐시

  • 캐시는 불필요한 데이터 전송을 줄여 네트워크 요금으로 인한 비용을 줄여준다.
  • 캐시는 네트워크 병목을 줄여준다. 대역폭을 늘리지 않고도 페이지를 빨리 불러 올 수 있음
  • 캐시는 원 서버에 대한 요청을 줄여준다.
  • 캐시는 거리로 인한 지연을 줄여준다.

- 불필요한 데이터 전송

: 불필요한 데이터 전송은 값비싼 네트워크 대역폭을 잡아먹고, 전송을 느리게 만들며, 웹 서버 부하를 준다. 캐시는 첫 번째 서버 응답은 캐시에 보관되어, 뒤이으은 요청들에 대한 응답으로 사용할 수 있다.

 

- 대역폭 병목

: 대역폭은 큰 문서에 대해 현저한 지연을 일으키며, 속도는 네트워크 종류의 차이에 따라 달라진다. 클라이언트가 빠른 LAN에 있는 캐시로부터 사본을 가져온다면, 성능이 대폭 개선될 것이다.

 

- 갑작스런 요청 쇄도

: 많은 사람이 거의 동시에 웹 문서에 접근할 때, 웹 서버에 과부하를 준다. 이러한 문제에 대처하기 위해 캐싱은 특히 중요하다.

 

- 거리로 인한 지연

: 클라이언트 서버 사이에 라우터가 많지 않더라도, 빛의 속도 자체가 유의미한 지연을 유발한다. 이를 해결하기 위해 기계실 근처에 캐시를 설치해서 문서가 전송되는 거리를 줄일 수 있다.

 

적중과 부적중

  • 캐시 적중: 캐시 요청이 도착했을 때, 그에 대응하는 사본이 있는 경우 이를 이용해 요청을 처리하는 것
  • 캐시 부적중: 대응하는 사본이 없을 경우, 서버로 전달되는 것

재검사

: 캐시가 갖고있는 사본이 여전히 최신인지 서버를 통해 점검하는 것

캐시 적중보단 느리나, 서버로부터 객체 데이터를 받아올 필요가 없기 때문에 캐시 부적중보단 빠르다.

 

캐시된 객체를 재확인하기 위해 주로 If-Modified-Since 헤더를 이용한다.

 

- GET If-Modified-Since 요청이 서버에 도착했을 때,

  • 재검사 적중: 서버는 304 Not Modified 응답을 보낸다.
  • 재검사 부적중: 서버 객체와 캐시된 사본이 다를 경우, 콘텐츠 전체와 함께 200 OK 응답을 보낸다.
  • 객체 삭제: 서버 객체가 삭제되었을 경우, 404 Not Found 응답을 보내고 캐시는 사본을 삭제한다.

- 캐시 적중률 (문서 적중률)

: 캐시가 요청을 처리하는 비율

0~1 값으로 되어 있고, %로 표현되기도 한다. (0% 캐시 부적중, 100% 모든 요청이 캐시 적중)

 

- 바이트 적중률

: 캐시를 통해 제공된 모든 바이트의 비율

바이트 단위 적중률 100%는 모든 바이트가 캐시에서 왔고, 어떤 트래픽도 인터넷으로 나가지 않았음을 의미

 

문서 적중률과 바이트 적중률은 캐시 성능에 유용한 지표이다. 문서 적중률은 얼마나 많은 웹 트랜잭션을 외부로 보내지 않았는지를 보여주며, 바이트 적중률은 얼마나 많은 바이트가 인터넷으로 나가지 않았음을 보여준다. 바이트 단위 적중률 개선은 대역폭 절약을 최적화 한다.

 

- 적중과 부적중의 구별

: Date 헤더를 이용.

응답의 Date 헤더 값을 현재 시각과 비교하여, 응답의 생성일이 더 오래 되었다면 클라이언트는 응답이 캐시된 것임을 알 수 있다.

또 다른 방법으론, Age 헤더를 이용

 

캐시 토폴로지

  • 개인 전용 캐시
    • 한 명에게만 할당된 캐시
    • 많은 에너지나 저장공간을 활용하지 않으므로 작고 저렴
    • 자주 쓰이는 문서를 개인용 컴퓨터의 디스크와 메모리에 캐시해 놓고, 사용자가 캐시 사이즈와 설정을 수정할 수 있도록 허용
    • 도구 > 인터넷 옵션 > 검색 기록 > 설정 > 파일 보기에서 캐시를 들여다볼 수 있다.
  • 공용 캐시
    • 공유된 캐시로 사용자 집단에게 자주 쓰이는 페이지를 담는다.
    • 캐시 프락시 서버 혹은 프락시 캐시라 불리는 공유된 프락시 서버
    • 공유된 공용 캐시는 자주 찾는 객체를 단 한 번만 가져와 모든 요청에 대해 공유된 사본을 제공함으로써 네트워크 트레픽을 줄인다.
  • 프락시 캐시 계층들
    • 작은 캐시에서 캐시 부적중이 발생했을 때 더 큰 부모 캐시가 트래픽을 처리하도록 하는 계층을 만드는 방식
    • 클라이언트 주위에 작고 저렴한 캐시를 사용하고, 계층 상단에는 더 크고 강력한 캐시를 사용

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

: 서로 대화하여, 어떤 부모 캐시와 대화할 것인지, 요청이 캐시를 완전히 우회해서 원 서버로 바로 가도록 할 것인지에 대한 캐시 커뮤니케이션 결정을 동적으로 내린다.

 

콘텐츠 라우팅을 위해 설계된 캐시들이 하는 일:

  • URL에 근거하여, 부모 캐시와 원 서버 중 하나를 동적으로 선택한다.
  • URL에 근거하여 특정 부모 캐시를 동적으로 선택
  • 부모 캐시에게 가기 전, 캐시된 사본을 로컬에서 찾는다.
  • 다른 캐시들이 그들의 캐시된 콘텐츠에 부분적으로 접근할 수 있도록 허용하되, 그들의 캐시를 통한 인터넷 트랜짓(트래픽이 다른 네트워크로 건너가는 것)은 허용하지 않음

캐시 처리 단계

  1. 요청 받기 - 캐시는 네트워크로부터 도착한 요청 메시지를 읽는다.
  2. 파싱 - 메시지 파싱하여 URL과 헤더를 추출
  3. 검색 - 로컬 복사본이 있는지 검사하고 사본이 없다면 사본을 받아온다.
  4. 신선도 검사 - 캐시된 사본이 충분히 신선한지 검사하고, 신선하지 않다면 서버에게 물어본다.
  5. 응답 생성 - 캐시는 새로운 헤더와 캐시된 본문으로 응답 메시지를 만든다.
  6. 발송 - 클라이언트에게 응답을 돌려준다.
  7. 로깅 - 로그파일에 트랜잭션에 대해 서술한 로그 하나를 남긴다.

사본을 신선하게 유지하기

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

 

- 문서 만료

: Cache-Control, Expires라는 특별한 헤더들을 이용해 원 서버가 각 문서에 유효기간을 붙일 수 있게 해준다.

 

유효 기간과 나이

  • Expires => 절대 유효기간을 명시한다. 유효기간이 경과했다면 문서는 더이상 신선하지 않다.
  • Cache-Control: max-age => max-age 값은 문서의 최대 나이를 정의한다. 제공하기엔 더 이상 신선하지 않다고 간주될 때까지 경과한 시간의 합법적인 최댓값을 의미

- 서버 재검사

: 캐시가 원 서버에게 문서가 변경되었는지의 여부를 물어볼 필요가 있음을 의미

 

- 조건부 메서드와 재검사

: HTTP는 캐시가 서버에게 '조건부 GET'이라는 요청을 보낼 수 있도록 해준다. 이 요청은 서버가 갖고 있는 문서가 캐시가 갖고 있는 것과 다른 경우에만 객체 본문을 보내달라고 하는 것이다.

 

  • If-Modified-Since: <date(캐시된 마지막 수정일)> => 만약 문서가 주어진 날짜 이후로 수정되었다면 요청 메서드를 처리
  • If-None-Match: <tags> => 마지막 변경된 날짜 대신, 서버는 문서에 대한 일련번호와 같이 동작하는 특별한 태그를 제공 (엔터티 태그 재검사)

캐시 제어

- 문서가 만료되기 전까지 얼마나 오랫동안 캐시될 수 있게 할 것인지 서버가 설정할 수 있는 방법

  • Cache-Control: no-store 헤더를 응답에 첨부
  • Cache-Control: no-cache 헤더를 응답에 첨부
  • Cache-Control: must-revalidate 헤더를 응답에 첨부
  • Cache-Control: max-age 헤더를 응답에 첨부
  • Expires 날짜 헤더를 응답에 첨부
  • 아무 만료 정보도 주지 않고 캐시가 스스로 결정

- no-cache와 no-store

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

 

- Max-Age 응답 헤더

: 신선하다고 간주되었던 문서가 서버로부터 온 이후로 흐른 시간 (초로 나타냄)

 

- expires 응답 헤더

: 실제 만료 날짜를 명시

 

- Must-Revalidate 응답 헤더

: 캐시가 이 객체의 신선하지 않은 사본을 원 서버와의 최초의 재검사 없이는 제공해서는 안 됨을 의미

 

- 휴리스틱 만료

: 응답이 max-age헤더나 Expires헤더 중 어느 것도 포함하지 않고 있다면, 경험적인 방법으로 최대 나이를 계산할 것이다.

 

*LM 인자 알고리즘

: 휴리스틱 만료 알고리즘의 하나, 최근 변경 일시를 문서가 얼마나 자주 바뀌는지에 대한 추정에 사용

$마지막_수정_이후로_경과한_시간 = max(0, $서버의_Date - $서버의_Last_Modified);
$서버_신선도_한계 = int($마지막_수정_이후로_경과한_시간 * $lm_인자);

 

- 클라이언트 신선도 제약

: 프락시 캐시의 신선하지 않은 콘텐츠를 강제로 갱신시켜 주는 리프레시나 리로드 버튼을 갖고 있다.

 

캐시 제어 설정

  • 아파치로 HTTP 헤더 제어하기
  • HTTP-EQUIV를 통한 HTML 캐시 제어

캐시와 광고

: 캐시는 사용자를 도와 더 좋은 경험을 제공하고, 또한 네트워크 사업자들이 트래픽을 줄일 수 있도록 도와준다.

 

- 광고 회사의 딜레마

: 캐시가 모든 곳에 있다면 콘텐츠 제공자는 대용량 멀티프로세서 웹 서버가 필요하지 않을 것이고, 같은 데이터를 몇 번이고 보여주기 위해 네트워크 서비스 요금을 지불할 필요도 없을 것이다. 또한 광고를 빠르게 보여줌으로서 더 많은 광고를 보게 할 수 있다.

 

- 퍼블리셔의 응답

: 광고회사들은 캐시가 광고 시청 수를 가로채지 못하도록 광고를 CGI 게이트웨이를 통해 제공하여 모든 종류의 '캐시 무력화' 기법을 사용한다. (매 접근마다 광고 URL을 고쳐쓴다.)

 

- 로그 마이그레이션

: 이상적인 해결책은 서버로 요청이 가지 않도록 하는 것이다. 결국 캐시는 모든 적중의 로그를 유지할 수 있다. 그러나 적중 로그는 크기 때문에 옮기기 어렵고 인증과 프라이버시 이슈도 있다.

 

- 적중 측정과 사용량 제한

: "HTTP를 위한 간단한 캐시 적중량 측정과 사용량 제한"은 더 간단한 방법을 정의한다.

=> HTTP에 특정 URL에 대한 캐시 적중 횟수를 정기적으로 서버에게 돌려주는 Meter라는 새 헤더 하나를 추가한다.

 

추가적으로, 서버는 캐시가 서버에게 보고하기 전까지 사용량을 제한할 수 있다. 캐시가 원 서버에게 보고하기 전에 캐시된 리소스가 얼마나 많이 사용될 수 있는지 서버가 제어할 수 있게 해준다.