[HTTP 완벽 가이드] - 캐시

Lee Jeong Min·2022년 4월 8일
1

네트워크

목록 보기
14/17
post-thumbnail

캐시

웹 캐시란 자주 쓰이는 문서의 사본을 자동으로 보관하는 HTTP 장치이다.

캐시의 혜택

  • 불필요한 데이터 전송 줄여 네트워크 요금으로 인한 비용을 낮춤
  • 네트워크 병목을 줄여줌
  • 원 서버에 대한 요청을 줄여줌
  • 거리로 인한 지연을 줄여줌

불필요한 데이터 전송

복수의 클라이언트들이 접근할 때, 서버가 같은 문서를 클라이언트에게 다 전송하기보다 캐시를 이용하여 첫 번째 서버 응답은 캐시에 보관시키고, 그 뒤의 요청들의 응답으로 사용하는 것이 원 서버의 중복 트래픽 낭비를 줄여준다.

대역폭 병목

많은 네트워크가 원격 서버보다 로컬 네트워크 클라이언트에 더 넓은 대역폭을 제공한다.

빠른 이더넷 → 100메가비트/초

↕️

전화식 모뎀 → 56킬로비트/초

5MB 기준 파일을 전송하는데 걸리는 시간은 각각 0.42초 와 749초(12분 이상) 이다.

갑작스런 요청 쇄도

특정 사건에 의해 원 서버로의 요청이 급격하게 증가하면 네트워크와 웹 서버의 심각한 장애를 야기시킨다.

이러한 경우 캐싱은 웹 서버의 과부화를 막는데 도움을 준다.

거리로 인한 지연

빛의 속도로 통신이 된다 하더라도, 절대적인 거리로 인해 요청과 응답 사이에 뚜렷한 지연이 발생하게 된다. (병렬이면서 keep-alive인 커넥션이라 하더라도 지연 발생!)

이런 경우 근처에 캐시를 설치해서 문서가 전송되는 거리를 줄일 수 있다.

적중과 부적중

캐시가 모든 문서의 사본을 저장하지는 않기에 캐시에 요청이 도착했을 때, 이에 대응하는 사본이 있다면 이를 캐시 적중(cache hit)이라고 하고, 없다면 원 서버로 전달하는데 이를 캐시 부적중(cache miss)이라고 부른다.

캐시는 신선한 상태를 유지하는 것이 중요!

재검사

원 서버의 콘텐츠와 캐시의 콘텐츠가 다를 수 있으므로 이를 검사해야한다. 이러한 신선도 검사를 HTTP 재검사라고 부른다. 물론 언제든지 검사를 할 수 있지만 네트워크 대역폭 문제로 충분히 오래된 경우에만 재검사를 한다.

콘텐츠가 변경되지 않은경우 서버는 304 Not Modfied응답을 보내며 이를 재검사 적중 혹은 느린 적중이라고 부른다.

순수 캐시 적중 > 재검사 적중(원 서버와 검사를 할 필요) > 캐시 부적중(서버로부터 데이터 받아옴, 실패한 재검사) 순으로 시간차이가 남(순수 캐시적중이 가장 빠름)

캐시된 객체를 재확인하기 위한 도구중 가장 많이 쓰이는 것: If-Modified-Since 헤더

→ 캐시된 시간 이후에 변경된 경우에만 사본을 보내달라는 의미!

GET If-Modified-SInce요청이 서버에 도착했을 때 일어날 수 있는 세가지 상황

  • 서버 콘텐츠가 변경되지 않은 경우(재검사 적중)
  • 서버 콘텐츠가 변경된 경우(재검사 부적중)
  • 객체가 삭제된 경우(객체 삭제)

재검사 적중

서버는 클라이언트에게 HTTP 304 Not Modified 응답을 보냄 (여전히 신선하다는 응답)

재검사 부적중

서버는 콘텐츠 전체와 함께 평범한 HTTP 200 OK 응답을 클라이언트에게 보낸다.

객체 삭제

서버는 404 Not Found 응답을 돌려보내며 캐시는 사본을 삭제한다.

적중률

0%: 모든 요청이 캐시 부적중

100%: 모든 요청이 캐시 적중

캐시 관리자는 캐시 적중률이 100%에 가까울 수록 좋아하지만 오늘날 적중률 40%면 웹 캐시로 괜찮은 편이다.

바이트 적중률

문서들이 모두 같은 크기인 것은 아니기 때문에 문서 적중률이 모든 것을 말해주지는 않는다.

즉 바이트 적중률은 크기 때문에 전체 트래픽에 더 영향을 끼치는 것을 인지하여 이를 수치화한 것이다.

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

문서 적중률은 얼마나 많은 웹 트랜잭션을 외부로 내보내지 않았는지 보여주고, 이를 개선하면 전체 대기시간(지연)이 줄어든다. 바이트 단위 적중률은 얼마나 많은 바이트가 인터넷으로 나가지 않았는지 보여주며 이 부분의 개선은 대역폭 절약을 최적화한다.

적중과 부적중의 구별

캐시가 적중이거나 부적중했는지 클라이언트는 항상 응답으로 200 OK를 받으므로 알 길이 없다. 이러한 경우

Date 헤더를 이용하여 현재 시각과 비교하여 응답의 생성일이 더 오래되었다면 클라이언트는 응답이 캐시된 것임을 알아낼 수 있다. 캐시된 응답을 감지하는 또 다른 방법으로 응답이 얼마나 오래되었는지 말해주는 Age 헤더를 이용하는 것이다.

캐시 토폴로지

  • 개인 전용 캐시: 한명에게만 할당된 캐시
  • 공용 캐시: 공용 캐시

개인전용 캐시

개인 전용 캐시는 많은 에너지나 저장 공간을 필요로 하지 않으므로, 작고 저렴할 수 있다.

공용 프락시 캐시

공용 캐시는 여러 사용자가 접근하기 때문에, 불필요한 트래픽을 줄일 수 있는 더 많은 기회가 있다.(네트워크 트래픽을 줄일 수 있음)

프락시 캐시 계층들

두 단계 캐시 계층으로 나누어 클라이언트 주위에는 작고 저렴한 캐시를 이용하고, 계층 상단에는 많은 사용자들에 의해 공유되는 문서를 유지하기 위해 더 크고 강력한 캐시를 사용하자는 것.

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

위의 프락시 캐시 계층처럼 두 단계 캐시 계층으로 나누는 것이 아닌 몇몇 네트워크 아키텍처는 복잡한 캐시망을 만든다. 캐시망 안에서의 콘텐츠 라우팅을 위해 설계된 캐시들은 다음에 나열된 일들을 모두 할 수 있을 것이다.

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

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

캐시 처리 단계

HTTP GET 메시지 하나를 처리하는 기본적인 캐시처리 절차는 일곱 단계로 이루어져있다.

  1. 요청 받기 - 캐시는 네트워크로부터 도착한 요청 메시지를 읽는다.
  2. 파싱 - 캐시는 메시지를 파싱하여 URL과 헤더들을 추출한다.
  3. 검색 - 캐시는 로컬 복사본이 있는지 검사하고, 사본이 없다면 사본을 받아온다.(이후 로컬에 저장)
  4. 신선도 검사 - 캐시는 캐시된 사본이 충분히 신선한지 검사하고, 신선하지 않다면 변경사항이 있는지 서버에게 물어본다.(사본을 신선도 한계를 넘을 정도로 너무 오래 갖고 있었다면 객체는 신선하지 않은 것으로 간주하여 서버와 재 검사가 필요하다)
  5. 응답 생성 - 캐시는 새로운 헤더와 캐시된 본문으로 응답 메시지를 만든다. 캐시 또한 캐시 신선도 정보를 삽입(cache-control, age, expires 헤더)하며 요청이 프락시 캐시를 거쳐갔음을 알려주는 Via 헤더를 삽입한다. 또한 캐시가 Date 헤더를 조정해서는 안되며 Date 헤더는 그 객체가 원 서버에서 최초로 생겨난 일시를 표시하는 것이다.
  6. 발송 - 캐시는 네트워크를 통해 응답을 클라이언트에게 돌려준다.
  7. 로깅 - 선택적으로, 캐시는 로그파일에 트랜잭션에 대해 서술한 로그 하나를 남긴다.

캐시 처리 플로 차트

사본을 신선하게 유지하기

캐시된 사본 문서가 서버의 문서와 항상 일치하는 것은 아니기 때문에 서버의 데이터와 일치하도록 관리되어야 한다. → 서버와 충분히 일치하도록 유지할 수 있게 해주는 메커니즘을 문서 만료와 서버 재검사라고 부른다.

문서 만료

HTTP는 Cache-ControlExpires라는 특별한 헤더들을 이용해서 원 서버가 각 문서에 유효기간을 붙일 수 있게 해준다. → 콘텐츠가 얼마나 오랫동안 신선한 상태로 보일 수 있는지 결정

캐시 문서가 만료되면, 캐시는 반드시 서버와 문서에 변경된 것이 있는지 검사해야하며 만약 그렇다면 신선한 사본을 얻어와야 한다.

유효기간과 나이

Cache-Control: max-age → max-age 값은 문서의 최대 나이를 정의

Expires → 절대 유효기간을 명시

서버 재검사

캐시된 문서가 만료되었다는 것 → 검사할 시간이 되었음을 의미 = 서버 재검사

  • 재검사 결과 콘텐츠 변경 → 새로운 사본을 가져와 오래된 데이터 대신 저장한 뒤 클라이언트에게 보냄
  • 재검사 결과 콘텐츠 변경X → 새 만료일을 포함한 새 헤더들만 가져와서 캐시 안의 헤더들을 갱신

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

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

조건부 메서드와의 재검사

HTTP는 캐시가 서버에게 ‘조건부 GET’ 이라는 요청을 보낼 수 있도록 해준다.

재검사를 효율적으로 만들어줌

If-Modified-Since: → 만약 문서가 주어진 날짜 이후로 수정되었다면 요청 메서드를 처리, Last Modified 서버 응답 헤더와 함게 사용된다.

If-None-Match: → 마지막 변경된 날짜를 맞춰보는 대신, 서버는 문서에 대한 일련번호와 같이 동작하는 특별한 태그를 제공할 수 있다. (캐시된 태그가 서버에 있는 문서의 태그와 다를 때만 요청 처리!)

If-Modified-Since: 날짜 재검사

흔히 IMS 요청이라고 불리며 서버에게 리소스가 특정 날짜 이후로 변경된 경우에만 요청한 본문을 보내달라고 함

If-Modified-Since 헤더는 서버 응답 헤더의 Last-Modified 헤더와 함께 동작한다.

변경이 없는 경우 304 반환하고 변경되었다면 새 본문과 함께 200을 반환한다.

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

이 태그는 다음과 같이 최근 변경 일시 재검사가 적절히 행해지기 어려운 상황에 쓰인다.

  • 어떤 문서는 일정 간격으로 다시 쓰여지지만 실제로는 같은 데이터를 포함한다.
  • 어떤 문서들의 변경은 전 세계의 캐시들이 그 데이터를 다시 읽어들이기엔 사소한 것일 수도 있다.
  • 어떤 서버들은 그들이 갖고 있는 페이지에 대한 최근 변경 일시를 정확하게 판별할 수 없다.
  • 1초보다 작은 간격으로 갱신되는 문서를 제공하는 서버들에게는, 변경일에 대한 1초의 정밀도는 충분하지 않을 수 있다.

따라서 이러한 경우 엔터티 태그를 사용하여 엔터티 태그가 변경되었다면 캐시는 새 문서의 사본을 얻기 위해 If-None-Match 조건부 헤더를 사용한다.(여러개의 엔터티 태그를 포함시키는것도 가능!)

약한 검사기와 강한 검사기

약한 검사기: 캐시된 사본을 무효화시키지 않고 문서를 살짝 고칠 수 있게 허용하는 것(콘텐츠가 조금 변경되었더라도 ‘그 정도면 같은것'이라고 서버가 주장할 수 있도록 해줌)

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

강한 검사기: 콘텐츠가 바뀔때마다 바뀜

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

엔터티 태그 반환한 경우 → 엔터티 태그 검사기 사용

Last-Modified 값만 반환한 경우 → If-Modified-Since 검사 사용

둘다 사용한 가능한 경우 두 가지 재검사 정책을 모두 사용

캐시 제어

HTTP는 문서가 만료되기 전까지 얼마나 오랫동안 캐시될 수 있게 할 것인지 서버가 설정할 수 있는 여러 가지 방법을 정의한다.

  • Cache-Control: no-store → 응답의 사본을 만드는 것을 금지
  • Cache-Control: no-cache → 서버와 재검사를 하지 않고서는 캐시에서 클라이언트로 제공 X
Cache-Control: no-store
Cache-Control: no-cache
Pragma: no-cache // HTTP/1.0+와의 하위호환성을 위해 HTTP/1.1에 포함되어 있다. 이러한 경우를 제외하고는 Cache-Control: no-cache사용!

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

  • Cache-Control: must-revalidate → 캐시가 이 객체의 신선하지 않은 사본을 원 서버와의 최초의 재검사 없이는 제공해서는 안 됨을 의미한다. 또한 캐시가 신선도 검사를 시도했을 때, 원 서버가 사용할 수 없는 상태라면 캐시는 반드시 504 Gateway Timeout error를 반환해야 한다.
  • Cache-Control: max-age
Cache-Control: max-age=3600
Cache-Control: s-maxage=3600

s-maxage 헤더는 공유된(공용) 캐시에만 적용된다

  • Expires → 초 단위의 시간 대신 실제 만료 날짜
Expires: Fri, 05 Jul 2002, 05:00:00 GMT

그러나 많은 서버가 동기화되어 있지 않거나 부정확한 시계를 갖고 있어서 만료를 절대시각 대신 경과된 시각으로 표현하는 것이 낫다고 판단함. 또한 Expires: 0와 같은 문법은 문법 위반이며 문제를 발생시킬 수 있다.

  • 아무 만료 정보도 주지 않고 캐시가 스스로 체험적인(휴리스틱) 방법으로 결정
    • 경험적인 방법으로 최대 나이 계산
    • LM 인자 알고리즘(캐시된 문서가 변경된 것이 상당히 예전이라면 안정적인 문서로 판단하여 캐시에 더 오래보관, 캐시된 문서가 최근에 변경되었다면 짧은 기간 동안만 캐시)
    • 아무런 단서가 없다면 기본 신선도 유지기간 설정(1시간 ~ 하루)

클라이언트 신선도 제약

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

지시어목적
Cache-Control: max-stale Cache-Control: max-stale = <s>캐시는 신선하지 않은 문서라도 자유롭게 제공할 수 있다. 만약 <s> 매개변수가 지정되면 클라이언트는 만료시간이 그 매개변수의 값만큼 지난 문서도 받아들인다.(느슨하게 함)
Cache-Control: min-fresh = <s>클라이언트는 지금으로부터 적어도 <s>초 후까지 신선한 문서만을 받아들인다.(엄격하게 함)
Cache-Control: max-age = <s>캐시는 <s> 초보다 오랫동안 캐시된 문서를 반환할 수 없다. 나이가 유효기간을 넘어서게 되는 max-stale 지시어가 함께 설정되지 않는 이상, 이 지시어는 캐싱 규칙을 더 엄격하게 만든다.
Cache-Control: no-cache Pragma: no-cache이 클라이언트는 캐시된 리소스는 재검사하기 전에는 받아들이지 않을 것이다.
Cache-Control: no-store이 캐시는 저장소에서 문서의 흔적을 최대한 빨리 삭제해야한다. 민감한 정보가 포함되어 있기 때문
Cache-Control: only-if-cached클라이언트는 캐시에 들어있는 사본만을 원한다.

캐시 제어 설정

웹 서버에서 캐시 제어와 만료 HTTP 헤더들을 설정하는 서로 다른 메커니즘에 대해서 알아보자

아파치로 HTTP헤더 제어하기

  • mod_headers: 개별 헤더들을 설정
<File *.html>
  Header set Cache-control no-cache
</Files>
  • mod_expires: Expires 헤더를 자동으로 생성하는 프로그램 로직을 제공한다.
  • mod_cern_meta: HTTP 헤더들의 파일을 특정 객체와 연결시켜줌

HTTP-EQUIV를 통한 HTML 캐시 제어

이 태그는 HTML 문서의 최상단에 위치하여 문서와 연동되어야 하는 HTTP 헤더들을 정의한다.

그러나 이 방법은 문서의 캐시 동작을 제어하는 서투른 방법으로, 유일하게 확실한 방법은 올바르게 설정된 서버가 보내온 HTTP 헤더를 이용하는 것이다.

자세한 알고리즘

이 부분의 내용은 캐시와 관련한 나이, 신선도 계산 방법을 다루고 있어서 책을 보는것으로 정리.

클록 스큐: 두 컴퓨터의 시계 설정 차이로 인한 문제

캐시와 광고

캐시는 사용자를 도와 더 좋은 경험을 제공하고, 네트워크 사업자들이 트래픽을 줄일 수 있도록 지원하지만 아래와 같은 문제가 있을 수 있다.

  • 광고 콘텐츠 제공과 관련하여 캐시로 인해 원 서버가 HTTP 접근을 수신하지 않게 되어 만약 접근 횟수로 돈을 번다면 문제가 있을 수 있다.
  • 이를 캐시가 가로채지 못하도록 ‘캐시 무력화'기법을 사용하는데 이러한 광고 시청 수를 관리하려는 시도는 캐싱의 긍정적인 효과를 감소시킨다.
  • 대안으로 원 서버와 재검사하도록 캐시를 설정하는 것이 있지만 이는 트랜잭션을 느리게 만든다.
profile
It is possible for ordinary people to choose to be extraordinary.

0개의 댓글