본격적으로 캐시에 관련하여 정리를 하기 전에 핵심적인 내용들을 먼저 적어놓고 들어가겠습니다.
캐시(Cache)는 데이터 또는 요청의 결과를 임시로 저장하는 장소를 의미합니다.
캐시의 주요 역할은 다음과 같습니다.
캐시의 종류는 다음과 같습니다.
캐시의 한계는 다음과 같습니다.
우선 이와 같이 정리를 해놓고 구체적인 내용들을 살펴봅시다.
위에서도 언급했듯이, 캐시를 사용하면 여러 가지 이점을 가져올 수 있습니다.
먼 거리의 통신의 경우 WAN을 사용해야 하고, 해당 통신을 사용할 경우 전파 지연으로 인한 레이턴시를 피할 수 없습니다.
따라서, 이러한 먼 거리의 통신에서 더 높은 성능을 가져오기 위해 클라이언트로부터 더 가까운 웹 캐시 서버를 설치할 수 있을 것입니다.
이렇게 될 경우 클라이언트의 요청이 거쳐가야 되는 트래픽은 더욱 짧아질 것이고, 네트워크 망에서 존재하는 시간 또한 짧아질 것입니다.
이것은 전체 트래픽을 낮추는 효과를 가져올 것이고, 병목 현상을 줄어드는 것을 기대할 수 있습니다.
트래픽이 원 서버로 몰릴 경우, 원 서버에 부하가 걸릴 수 있기 때문에 캐시 서버에 복사된 사본을 저장하여 사용자의 요청들을 분산시킬 수 있습니다.
캐시를 사용할 때 한계점에 정리를 해놓은 것 처럼 중요한 것은 데이터의 일관성을 지켜줘야 하는 점입니다.
웹 캐시 서버에서 복사된 사본을 가지고 있고 해당 사본의 출처 리소스가 많이 변경되었을 경우 사용자는 변경된 리소스를 받아야만 합니다.
사용자의 요청이 캐시 서버에 존재하는 리소스일 경우 이것을 캐시 적중(Cache hit)라고 하고, 사본이 없다면 캐시 부적중(Cache miss)라고 합니다.
캐시 부적중이 발생했을 경우, 원 서버로 요청을 보내서 리소스를 받아오면 됩니다.
좀 더 복잡한 경우는 캐시 서버에 사본이 존재하지만 이것이 최신 리소스인지 애매한 경우입니다.
이러한 경우를 위해서 재검사(Revalidation)이라 하는 '신선도 검사'가 존재합니다.
이것을 위해서 대표적으로 사용되는 HTTP 헤더 필드는 If-Modified-Since
헤더 필드입니다. 서버에게 보내는 GET 요청에 이 헤더를 추가하면 캐시된 ㅣ시간 이후에 변경된 경우에만 사본을 보내달라는 의미가 됩니다.
만약, 서버 객체(리소스)가 변경되지 않았다면 서버는 클라이언트에게 작은 HTTP 304 Not Modified
응답을 보낼 것입니다.
서버 객체가 캐시된 사본과 다르다면, 서버는 콘텐츠 전체와 함께 평범한 HTTP 200 OK
응답을 클라이언트에게 보낼 것입니다.
서버 객체가 삭제되었다면, 서버는 404 Not Found
응답을 돌려보내서, 캐시는 사본을 삭제합니다.
캐시 적중률(문서 적중률)은 40% 정도면 웹 캐시로 괜찮은 편이라고 합니다.
전체 트래픽을 고려한 바이트 단위 적중률 측정도 있습니다. 이것은 문서 단위로 적중률을 체크하는 것이 아닌 바이트 단위로 적중률을 체크함으로써 각 문서마다 크기가 달라도 보다 정확하게 트래픽을 체크할 수 있습니다.
여기까지 정리를 해봤다면, 한가지 궁금한 점이 생길 수 있다.
클라이언트는 요청으로부터 받은 리소스가 복사된 사본인지, 본래 객체인지 구별할 수 있을까?
이것을 구분하려면 다음과 같은 헤더들을 이용할 수 있겠습니다.
캐시도 프록시와 마찬가지로 계층 구조를 이룰 수 있는데, 이것은 굉장히 자주 사용되는 구조입니다.
대표적으로 운영 체제의 CPU와 메모리 구조에서도 캐시 메모리가 계층 구조로 이루어져 있습니다.
캐시 서버도 이와 비슷한 목적으로 사용되며 확장 버전 정도로 이해할 수 있습니다.
캐시망 안에서의 콘텐츠 라우팅을 위해 설계된 캐시들은 다음에 나열된 일들을 모두 할 수 있을 것입니다.
HTTP GET 메시지 하나를 처리하는 기본적인 캐시 처리 절차는 일곱 단계로 이루어져 있습니다.
추가적인 개념들을 정리해보자면 다음과 같습니다.
우선, 3단계인 검색 단계에서 로컬 복사본이 있는지 검사하는 것은 본문만을 포함하는 것이 아닙니다. 캐시된 객체는 서버 응답 본문과 원 서버 응답 헤더를 포함하고 있으므로, 캐시 적중 동안 올바른 서버 헤더가 반환될 수 있습니다.
5단계인 응답 생성에서 캐시는 클라이언트에 맞게 헤더를 조정해야 하는 책임이 있습니다.
클라이언트의 요구 사항에 맞춰서 헤더를 적절하게 번역해주고, 필요한 경우 캐시 신선도 정보를 삽입하거나 Via 헤더
혹은 Date 헤더
를 추가하여 캐시 서버를 사용했음을 알릴 수 있습니다.
그렇다면, 캐시 서버는 문서가 만료되었다는 사실은 무엇을 통해서 알 수 있을까?
HTTP는 Cache-Control
과 Expires
라는 특별한 헤더들을 이용해서 원 서버가 각 문서에 유효기간을 붙일 수 있게 해줍니다.
Cache-Control: max-age
: max-age
값은 문서의 최대 나이를 정의한다.Expires
: 절대 유효기간을 명시한다.
Expires
응답 헤더는 deprecated 되었습니다. HTTP를 설계한 사람들은, 많은 서버가 동기화되어 있지 않거나 부정확한 시계를 갖고 있기 때문에, 만료를 절대시각 대신 경과된 시간으로 표현하는 것이 낫다고 판단했기 때문입니다.
위와 같은 것들을 이용해서 검사를 수행할 수 있고, 만약 복사된 사본이 재검사를 해야하는 경우 어떻게 동작하는지 알아보자.
복사된 사본의 재검사 요청의 결과의 경우 삭제된 경우를 제외하고 두 가지가 존재합니다.
변경 되었을 경우에는 새로운 객체를 받아올 필요가 있지만 변경되지 않았다면 굳이 객체를 받아오면서 불필요한 오버헤드를 만들 필요가 없습니다.
그래서 여기서 등장하는 것이 조건부 메서드 요청입니다.
If-Modified-Since: <date>
: 만약 문서가 주어진 날짜 이후로 수정되었다면 요청 메서드를 처리합니다.If-None-Match: <tags>
: 마지막 변경된 날짜를 맞춰보는 대신, 서버는 문서에 대한 일련번호와 같이 동작하는 특별한 태그(ETag
)를 제공할 수 있습니다.가장 흔히 쓰이는 캐시 재검사 헤더는 If-Modified-Since
이고, 이것은 Last-Modified
헤더와 함께 동작합니다.
304 Not Modified
응답 메시지를 클라이언트에게 돌려줍니다. 효율을 위해 본문은 보내지 않습니다. 응답은 필요한 헤더들을 포함하지만, 원래 돌려줘야 할 것에서 갱신이 필요한 것들만 보내줍니다.위의 동작과 같이 캐시는 변경되지 않는 사본의 업데이트는 헤더만 이루어지지고, 전송 과정에서 불필요한 오버헤드는 최대한 피함으로써 빠르게 동작하게 합니다.
하지만, 해당 방식에는 단점이 존재합니다.
이러한 단점들은 ETag
를 사용하는 If-None-Match
를 사용하면서 해결할 수 있습니다.
캐시의 검사기에는 두 가지 종류가 있습니다.
약한 검사기의 경우 W/
접두사를 활용합니다.
ETag: W/"v2.6"
If-None-Match: W/"v2.6"
언제 엔터티 태그를 사용하고 언제 Last-Modified 일시를 사용하는 것일까요?
그것은 서버가 어떠한 값을 반환했는지에 따라 달라집니다.
만약, 서버가 엔터티 태그만 반환했을 경우 엔터티 검사기로 진행합니다.
하지만, Last-Modified-Since만 반환했을 경우 해당 검사기를 사용합니다.
두 방식 모두 사용이 가능하다면, HTTP/1.0과 HTTP/1.1 캐시 모두 적절히 응답할 수 있도록 클라이언트는 각각을 위해 두 가지의 재검사 정책을 모두 사용해야 합니다.
HTTP는 문서가 만료되기 전까지 얼마나 오랫동안 캐시될 수 있게 할 것인지 서버가 설정할 수 있는 여러 가지 방법을 정의합니다. 우선순위대로 나열해보면 서버는,
하나씩 살펴봅시다.
우선 'no-store'가 표시된 응답은 캐시가 그 응답의 사본을 만드는 것을 금지합니다.
'no-cache'로 표시된 응답은 로컬 캐시 저장소에 저장될 수 있습니다. 다만 먼저 서버와 재검사를 하지 않고서는 캐시에서 클라이언트로 제공될 수 없을 뿐입니다.
Cache-Control: max-age 헤더는 신선하다고 간주되었던 문서가 서버로부터 온 이후로 흐른 시간이고, 초로 나타냅니다. 0으로 설정하여 캐시하지 않거나 혹은 매 접근마다 리프레시 하도록 요청할 수 있습니다.
Expires 응답 헤더는 초 단위의 시간 대신 실제 만료 날짜를 명시합니다. deprecated 되었습니다.
Cache-Control: must-revalidate 응답 헤더는 캐시가 이 객체의 신선하지 않은 사본을 원 서버와의 최초의 재검사 없이는 제공해서는 안 됨을 의미합니다.
캐시 설정을 느슨하게 해주는 지시어들도 존재하는데 그러한 것들이 있다는 것만 염두해두고 넘어갑시다.
이후에 웹 서버 종류별로 캐시를 설정하는 방법에 대해서 간략하게 제시하고 있습니다.
그리고 나이와 신선도 수명 계산하는 알고리즘에 대해서 소개하고 있습니다.
이 부분은 다루지 않겠습니다.