[7장] 캐시

janjanee·2022년 8월 1일
0
post-thumbnail

2020.12.13 작성글 이전


7장 캐시

7.1 불필요한 데이터 전송

복수의 클라이언트가 자주 쓰이는 원 서버 페이지에 접근할 때, 서버는 클라이언트들에게 각각 한 번씩 전송하게 된다. 같은 내용의 데이터 전송이 반복적으로 이루어진다.

이 불필요한 데이터 전송은 네트워크 대역폭을 잡아먹고, 전송을 느리게 하며, 웹 서버에 부하를 준다. 캐시를 사용하면, 첫 번째 서버 응답을 캐시에 보관하여 캐시된 사본이 뒤이은 요청들에 대한 응답으로 사용된다.

7.2 대역폭 병목

캐시는 네트워크 병목을 줄여준다. 클라이언트들이 서버에 접근하는 속도는, 그 경로에 있는 가장 느린 네트워크의 속도와 같다. 만약, 클라이언트가 빠른 LAN에 있는 캐시로 부터 사본을 가져온다면, 캐싱은 성능을 대폭 개선할 수 있다.

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

캐싱은 갑작스런 요청 쇄도에 대처하기 위해 특히 중요하다.

갑작스런 사건(뉴스, 속보, 스팸, 유명인사 관련)으로 인해 많은 사람이 동시에 웹 문서에 접근할 때 이런 일이 발생한다. 이로인한 트래픽 급증은 네트워크와 웹 서버의 심각한 장애를 발생시킨다.

7.4 거리로 인한 지연

대역폭이 문제가 되지 않더라도 순수한 거리 자체가 문제가 될 수 있다. 빛의 속도 그 자체가 유의미한 지연을 유발한다.

7.5 적중과 부적중

캐시에 요청이 도착했을 때, 만약 그에 대응하는 사본이 있다면 그를 이용해 요청이 처리될 수 있다. 이것을 캐시 적중이라고 부른다. 대응되는 사본이 없다면 원 서버로 전달되는데 이것을 캐시 부적중이라고 한다.

7.5.1 재검사(Revalidation)

캐시는 사본이 여전히 최신인지 서버를 통해 때때로 점검해야 한다. 이러한 검사를 HTTP 재검사라 부른다. 그러나 대부분의 캐시는 그 사본이 검사를 할 필요가 있을 정도로 충분히 오래된 경우에만 재검사를 한다.

HTTP 캐시는 객체를 재확인 하기위해 If-Modified-Since라는 헤더를 가장 많이 사용한다. 캐시된 시간 이후에 변경된 경우에만 사본을 보내달라는 의미가 된다.

  • 재검사 적중(느린적중) 캐시는 사본의 재검사가 필요할 때 재검사 요청을 보낸다. 서버는 304 Not Modified 응답을 보낸다. 캐시 적중 보다는 느리지만, 캐시 부적중 보다는 빠르다.
  • 재검사 부적중 서버 객체가 캐시된 사본과 다르다면, 서버는 콘텐츠 전체와 함께 평범한 HTTP 200 OK 응답을 클라이언트에게 보낸다.
  • 객체 삭제 서버 객체가 삭제되었다면, 서버는 404 Not Found 응답을 돌려보내며, 캐시 사본을 삭제한다.

7.5.2 적중률

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

  • 0% -> 모든 요청이 캐시 부적중(네트워크 너머로)
  • 100% -> 모든 요청이 캐시 적중(캐시에서 사본)

7.5.3 바이트 적중률

바이트 단위 적중률은 캐시를 통해 제공된 모든 바이트의 비율을 표현한다. 바이트 단위 적중률 100%는 모든 바이트가 캐시에서 왔으며, 어떤 트래픽도 인터넷으로 나가지 않았음을 의미한다.

문서 적중률과 바이트 단위 적중률은 둘 다 캐시 성능에 대한 유용한 지표다.

문서 적중률을 개선하면 전체 대기시간(지연)이 줄어든다. 바이트 단위 적중률의 개선은 대역폭 절약을 최적화한다.

7.5.4 적중과 부적중의 구별

응답의 생성일이 더 오래되었다면 클라이언트는 응답이 캐시된 것임을 알아낼 수 있다. 또는, Age 헤더를 확인한다.

7.6 캐시 토폴로지

  • 전용 캐사(private cache)
    • 한 명에게만 할당된 캐시
    • 한 명의 사용자가 자주 찾는 페이지를 담는다.
  • 공용캐시(public cache)
    • 사용자 집단에게 자주 쓰이는 페이지를 담는다.

7.6.1 개인 전용 캐시

웹 브라우저는 개인 전용 캐시를 내장하고 있다. 자주 쓰이는 문서를 개인용 컴퓨터의 디스크와 메모리에 캐시해놓고, 사용자가 캐시 사이즈와 설정을 수정할 수 있도록 허용한다.

7.6.2 공용 프락시 캐시

캐시 프락시 서버 혹은 프락시 캐시라고 불리는 특별한 종류의 공유된 프락시 서버다. 프락시 캐시는 로컬 캐시에서 문서를 제공하거나, 혹은 사용자의 입장에서 서버에 접근한다. 공용 캐시에는 여러 사용자가 접근하기 때문에, 불필요한 트래픽을 줄일 수 있다.

7.6.3 프락시 캐시 계층들

작은 캐시에서 캐시 부적중이 발생했을 때 더 큰 부모 캐시가 걸러 남겨진 트래픽을 처리하도록 하는 계층을 만드는 방식이 합리적인 경우가 많다.

캐시 계층이 깊다면 요청은 캐시의 긴 연쇄를 따라가게 된다. 프락시 연쇄가 길어질수록 각 중간 프락시는 현저한 성능 저하가 발생할 것이다.

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

몇몇 네트워크 아키텍처는 단순한 캐시 계층 대신 복잡한 캐시망을 만든다.

캐시망 안에서의 콘텐츠 라우팅을 위해 설계된 캐시들은 아래의 일들을 모두 할 수 있다.

  • URL에 근거하여, 부모 캐시 / 원 서버 중 하나를 동적으로 선택

  • URL에 근거하여 특정 부모 캐시를 도적으로 선택

  • 부모 캐시에 가기전에, 캐시된 사본을 로컬에서 찾기

  • 다른 캐시들이 그들의 캐시된 콘텐츠에 부분적으로 접근할 수 있도록 허용하되, 그들의 캐시를 통한

    트랜짓은 허용하지 않음

복잡한 캐시 사이의 관계는, 서로 다른 조직들이 상호 이득을 위해 그들의 캐시를 연결하여 서로를 찾아볼 수 있도록 해준다. 선택적인 피어링을 지원하는 캐시는 형제 캐시라고 불린다.

HTTP는 형제 캐시를 지원하지 않기 때문에 인터넷 캐시 프로토콜(ICP)나 하이퍼텍스트 캐시 프로토콜(HTCP)를 이용해 HTTP를 확장한다.

7.7 캐시 처리 단계

7.7.1 단계 1: 요청 받기

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

7.7.2 단계 2: 파싱

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

7.7.3 단계 3: 검색

캐시는 URL을 알아내고 그에 해당하는 로컬 사본이 있는지 검색한다. 캐시된 객체는 서버 응답 본문과 원 서버 응답 헤더를 포함하고 있으므로, 캐시 적중 동안 올바른 서버 헤더가 반환될 수 있다.

또한, 얼마나 오랫동안 캐시 되었는지, 얼마나 자주 사용되었는지 등에 대한 몇몇 메타 데이터를 포함한다.

7.7.4 단계 4: 신선도 검사

HTTP는 캐시가 일정 기간 동안 서버 문서의 사본을 보유할 수 있도록 해준다. 신선도 한계를 넘을 정도로 오래 갖고 있었다면, 그 객체는 신선하지 않은 것으로 간주되며 변경이 있었는지 검사하기 위해 서버와 재검사를 해야한다.

7.7.5 단계 5: 응답 생성

캐시는 캐시된 서버 응답 헤더를 토대로 응답 헤더를 생성한다. 또한, 캐시는 신선도 정보를 삽입하며(Cache-Control, Age, Expires 헤더), 또 요청이 프락시 캐시를 거쳐갔음을 알려주기 위해 종종 Via 헤더를 포함시킨다.

캐시가 Date 헤더를 조정해서는 안 된다는 것에 주의해야함!

7.7.6 단계 6: 전송

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

7.7.7 단계 7: 로깅

대부분의 캐시는 로그 파일과 캐시 사용에 대한 통계를 유지한다. 가장 많이 쓰이는 캐시 로그 포맷은 스퀴드 로그 포맷넷스케이프 확장 공용 로그 포맷이지만, 많은 캐시 제품이 커스텀 로그 파일을 허용한다.

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

7.8.1 문서 만료

HTTP는 Cache-Control과 Expires라는 특별한 헤더들을 이용해서 원 서버가 각 무서에 유효기간을 붙일 수 있게 해준다. 캐시된 문서가 만료되면, 캐시는 반드시 서버와 문서에 변경된 것이 있는 검사해야 하며, 만약 그렇다면 신선한 사본을 얻어 와야 한다

7.8.2 유효기간과 나이

헤더설명
Cache-Control: max-agemax-age 값은 문서의 최대 나이를 정의한다.
Expires절대 유효기간을 명시한다. 만약 유효기간이 경과했다면, 그 문서는 더 이상 신선하지 않다.

7.8.3 서버 재검사

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

  • 충분히 신선한 캐시된 사본
  • 원 서버와 재검사되었기 때문에, 충분히 신선하다고 확신할 수 있는 캐시된 사본
  • 에러 메시지(재검사 해야하는 원 서버가 다운된 경우)
  • 경고 메시지가 부착된 캐시된 사본(부정확하다면)

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

HTTP는 캐시가 서버에게 '조건부 GET'이라는 요청을 보낼 수 있도록 해준다. 조건부 GET은 GET 요청 메시지에 특별한 조건부 헤더를 추가함으로써 시작된다. 웹 서버는 조건이 참인 경우에만 객체를 반환한다.

HTTP는 다섯 가지 조건부 요청 헤더를 정의한다. 그 중 둘은 캐시 재검사를 할 때 가장 유용한 If-Modified-Since와 If-None-Match이다.

모든 조건부 헤더는 'If-' 접두어로 시작한다.

헤더설명

If-Modified-Since: |문서가 주어진 날짜 이후로 수정되었다면 요청 메서드를 처리한다. 이것은 캐시된 버전으로부터 콘텐츠가 변경된 경우에만 콘텐츠를 가져오기 위해 Last-Modified 서버 응답 헤더와 함께 사용된다. If-None-Match: |마지막 변경된 날짜를 맞춰보는 대신, 서버는 문서에 대한 일련번호와 같이 동작하는 특별한 태그를 제공할 수 있다. 캐시된 태그가 서버에 있는 문서의 태그와 다를 때만 요청을 처리한다.

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

가장 흔히 쓰이는 캐시 재검사 헤더이다. 'IMS' 요청으로도 불린다. 서버에게 리소스가 특정 날짜 이후로 변경된 경우에만 요청한 본문을 보내달라고 한다.

  • 문서가 주어진 날짜 이후에 변경되었다면, GET 요청은 성공한다. 새 문서가, 새로운 만료 날짜와 그 외

    다른 정보들이 담긴 헤더들과 함께 캐시에게 반환된다.

  • 문서가 변경되지 않았을 경우, 서버는 304 Not Modified 응답 메시지를 클라이언트에게 돌려준다.

    응답은 헤더들을 포함하지만, 갱신이 필요한 것들만 보내준다.

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

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

최근 변경 일시 재검사가 적절히 일어나기 어려운 상황이 몇 가지 있다.

  • 일정 시간 간격으로 다시 쓰여져서 시각만 변했을 뿐 내용은 동일한 경우
  • 어떤 문서들은 그 데이터를 다시 읽어들이기엔 사소한 것일 수 있다. (철자나 주석의 변경)
  • 페이지에 대한 최근 변경 일시를 정확하게 판별 할 수 없다.
  • 1초보다 작은 간격으로 갱신되는 문서를 제공하는 서버들에게는, 변경일에 대한 1초의 정밀도는 충분하지 않을 수 있다.
조건부 요청
GET /announce.html HTTP/1.0
If-None-Match: "v2.6"

---

응답
HTTP/1.0 304 Not Modified
Date: Mon, 14 Dec 2020, 11:24:33 GMT
ETag: "v2.6"
Expires: Fri, 18 Dec 2020, 06:00:00 GMT

v2.6 엔터티 태그가 변경 되었을 경우 새 문서의 사본을 달라고 요청한다. 그러나 변경된 것이 없으므로 304 Not Modified 응답이 돌아온다.

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

캐시가 객체에 대한 여러 개의 사본을 갖고 있는 경우, 여러 개의 엔터티 태그를 포함할 수 있다.

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

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

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

서버는 'W/' 접두사로 약한 검사기를 구분한다.

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

서버가 엔터티 태그를 반환했다면, 반드시 엔터티 태그 검사기를 사용해야 한다. 서버가 Last-Modified 값만을 반환했다면, 클라이언트는 If-Modified-Since 검사를 사용할 수 있다.

엔터티 태그와 최근 변경일시가 모두 사용 가능하다면, 클라이언트는 각각을 위해 두 가지의 재검사 정책을 모두 사용해야 한다.

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-store : 캐시가 그 응답의 사본을 만드는 것을 금지한다.

  • no-cache : 로컬 캐시 저장소에 저장될 수 있다. 다만 먼저 서버와 재검사를 하지 않고서는

    캐시에서 클라이언트로 제공될 수 없을 뿐이다.

7.9.2 Max-Age 응답 헤더

Cache-Control: max-age=3600
Cache-Control: s-maxage=3600

서버로부터 온 이후로 흐른 시간이고, 초로 나타낸다. s-maxage 헤더는 공유된(공용) 캐시에만 적용된다.

서버는 최대 나이먹음(0) 으로 설정함으로써, 캐시가 매 접근마다 문서를 캐시하거나 리프레시하지 않도록 요청할 수 있다.

7.9.3 Expires 응답 헤더

실제 만료 날짜를 명시하지만, 많은 서버가 동기화 되어있지않거나 부정확한 시계를 갖고있으므로 더 이상 사용하지 않기를 권한다.

7.9.4 Must-Revalidate 응답 헤더

캐시는 성능을 개선하기 위해 신선하지 않은(만료된) 객체를 제공하도록 설정할 수 있다. 만약 캐시가 만료 정보를 엄격하게 따르길 원한다면, 원 서버는 다음과 같은 Cache-Control을 붙일 수 있다.

Cache-Control: must-revalidate

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

7.9.5 휴리스틱 만료

유명한 휴리스틱 알고리즘의 하나인 LM 인자 알고리즘이 있다.

LM 인자 알고리즘은 최근 변경 일시를 문서가 얼마나 자주 바뀌는지에 대한 추정에 사용한다. LM 인자 알고리즘은 캐시가 서버와 대화 했을 때와 서버가 문서의 최근 변경 일시를 말했을 때의 시간차를 계산하고, 이 차의 일부분을 취하여, 이 일부분을 캐시의 신선도 지속기간으로 사용한다.

캐시는 일반적으로 신선도에 대한 아무런 단서가 없는 문서에 대해 기본 신선도 유지기간을 설정한다. (보통 한시간이나 하루정도)

7.9.6 클라이언트 신선도 제약

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

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

7.10 캐시 제어 설정

웹 서버들은 캐시 제어와 만료 HTTP 헤더들을 설정하는 서로 다른 메커니즘을 제공한다.

7.10.1 아파치로 HTTP 헤더 제어하기

아파치 웹 서버는 HTTP 캐시 제어 헤더를 설정할 수 있는 여러 가지 메커니즘을 제공한다.

  • mod_headers
  • mod_expires
  • mod_cern_meta

7.10.2 HTTP-EQUIV를 통한 HTML 캐시제어

불행히도 이 기능을 지원하는 웹 서버나 프락시는 거의 없다. 이 기능은 서버의 부하를 가중시키고, 설정값이 정적이고, HTML을 제외한 다른 타입의 파일은 지원하지 않기 때문이다.

문서의 캐시 제어 요청과 커뮤니케이션하는 유일하게 확실한 방법은 올바르게 설정된 서버가 보내온 HTTP 헤더를 이용하는 것이다.

7.11 자세한 알고리즘

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

    나이 = 문서가 우리의 캐시에 도착했을 때의 나이 + 사본이 얼마나 오래 우리의 캐시에 있었는지
  • 신선도 수명 계산

캐시된 문서의 나이를 알아내고 서버와 클라이언트의 제약조건에 따라 신선도 수명을 계산해야 한다. 신선도 수명은 서버와 클라이언트의 제약조건에 의존한다.

캐시는 사용자를 위해 봉사한다. 반드시 그들의 요구에 충실히 따라야 한다.

7.12 캐시와 광고

많은 콘텐츠 제공자가 광고를 통해 돈을 번다. 사용자가 광고를 볼 때마다 돈을 번다. 캐시는 원 서버가 실제 접근 횟수를 알 수 없게 숨길 수 있다. 만약 캐싱이 완벽하게 동작한다면 원 서버는 HTTP 접근을 전혀 수신하지 않게 된다. 만약 접근횟수에 따라 돈을 벌고 있다면, 이는 달갑지 않은 일일 것이다.

오늘날 캐시가 광고 시청 수를 가로채지 못하도록 모든 종류의 캐시 무력화 기법을 사용한다.

광고를 CGI 게이트웨이를 통해 제공한다. 그들은 매 접근마다 광고 URL을 고쳐쓴다.

불행히도 광고의 시청 수를 관리하려는 과하게 의욕적인 시도는, 몇몇 콘텐츠 제공자가 그들의 사이트에 대한 캐싱의 긍정적인 효과를 감소시킨다.

RFC 2227, HTTP를 위한 간단한 캐시 적중량 측정과 사용량 제한(Simple Hit-Metering and Usage-Limiting for HTTP)은 더 간단한 방법을 정의한다. 이 프로토콜은 HTTP에 때때로 특정 URL에 대한 캐시 적중 횟수를 정기적으로 서버에게 돌려주는 Meter라고 하는 새 헤더 하나를 추가한다. 이 방법은, 서버가 캐시된 문서가 적중한 횟수의 정기적인 업데이트를 캐시로부터 받는다.

profile
얍얍 개발 펀치

0개의 댓글