본문 바로가기
Front-end/웹성능 최적화

Cache-control로 캐시최적화하기

by img 2022. 7. 12.

Cache란?

콘텐츠 요청에 빠르게 응답하기 위해 서버와 클라이언트 사이에서 응답 콘텐츠의 사본을 저장하는 공간을 캐시라고 합니다. 이 캐시를 유지하고 처리해주는 별도의 서버를 캐시 서버라고 합니다. 캐시는 보통 클라이언트와 서버 사이에 존재하며, 서버의 성능을 크게 향상시키는 역할을 합니다. 웹은 HTML, 이미지, CSS, 자바스크립트 등 정적 콘텐츠가 많기 때문에 캐시의 역할이 중요합니다.

웹 캐시는 서버와 브라우저 중간에 존재하면서 최초 원본 콘텐츠 요청을 최종 서버에 보내 응답을 받은 후 그 복사본을 만들어 저장하고 사용자에게 응답합니다. 이후 같은 콘텐츠에 대한 요청이 웹 서버에서 원본을 가져오는 대신 캐싱 서버에서 복사본을 받아 원본 서버로의 트래픽을 줄이고 사용자의 요청에 대한 반응 속도를 빠르게 합니다. 

크롬 브라우저를 기준으로 웹 브라우저는 크게 2가지 방법으로 캐싱을 합니다. (브라우저 자체의 알고리즘으로 알아서 처리)
1. 메모리캐시 : RAM에 데이터를 저장해놓는 방식
2. 디스크 캐시 : 파일로 저장해놓고 파일을 읽어서 저장하는 방식

구글에서 disabled cache를 끄고(cache를 사용하겠다) 일반 새로고침을 하면 Network탭에서 메모리 캐시, 또는 디스크 캐시라는 항목을 볼 수 있습니다. 네트워크 탭을 연 다음 구글을 다시 들어가면 size에 디스크 캐시만 남아있고 메모리 캐시는 (거의) 없습니다. 메모리 캐시는 RAM에 저장을 하기 때문에 브라우저를 껐다 키면 브라우저가 사용하는 메모리 영역을 다 날려버렸기 때문입니다.


Cache-control

HTTP/1.1부터 명시적으로 캐시를 제어할 수 있는 헤더를 추가했는데 그것이 cache-control 헤더 입니다.  header에 cache-control이 있어야 캐시설정을 하는데, cache-control이 없으면 캐시에 대한 설정이 없단 얘기입니다. 

브라우저가 서버로 특정 리소스를 요청할 때 미리 지시문을 같이 줘야하는데, cache-control의 주요 '지시자' 항목은 다음과 같습니다.

1. no-cache
request 헤더에 no-cache설정이 된 경우, 캐싱된 응답을 받지 않고 이 요청을 원본 서버에 그대로 전달 해 원본 서버로부터 항상 최신의 응답을 받겠다는 의미입니다.
response헤더에 no-cache설정이 된 경우에는 캐싱된 데이터를 항상 서버에 검사를 맡는 과정을 거칩니다. 예를들어, 이미지가 캐싱되어 있다면, 이미지가 만료되었는지(바뀌었는지) 한번 물어보는 과정(조건부 요청)을 먼저 거치는 것입니다, 만약 만료가 되었거나 변경되었다면 새로운 이미지를 서버에서 받아서 가져옵니다(max-age=0과 동일하게 동작합니다)
어쨌든 원본서버에는 항상 다녀오게됩니다.

2. no-store
request, response 헤더 모두에서 동일하게 사용되며, "캐시를 사용하지 않겠다" 라는 의미입니다. no-cache는 항상 원본 서버로부터 받아와 최신의 상태로 유지되지만, 로컬 저장소에 저장되는 것 자체를 막는 것은 아닙니다, 하지만 no-store는 저장소에 저장되는 것 자체를 금지합니다.

3. public
응답 헤더에 사용할 수 있습니다. 
모든 캐시 서버에 캐시될 수 있고 사용자 제한 없이 모든 사용자에게 응답이 전달될 수 있습니다. 

4. private
원본서버가 일부 응답을 "특정 사용자에게만" 전달하는데에 목적이 있으므로, 최종 사용자 개인의 브라우저 환경에서만 캐싱을 하고, 외부 캐시서버(CDN같은 범용 캐시 서버)에서는 캐싱할 수 없게됩니다. 예를들어, 로그인을 해서 내 정보가 들어있는 페이지를 들어가려고 하는데, 내 브라우저가 아닌 만약 다른 외부서버에까지 내 정보가 캐싱되는 경우를 방지해줍니다. 응답 메시지를 어디에 캐시할 것인지 지정하기 위해 사용할 뿐, 그 자체로 개인정보를 보호하는 장치가 되지는 않습니다. 

5. max-age
캐시의 유효기간을 설정합니다. 예를들어, max-age=60이면 60초동안 캐시 적용, 600이면 600초(1분)동안 캐싱됩니다. max-age 시간이 지났어도 브라우저는 해당 캐시는 완전히 버려버리는 것이 아니라 그대로 리소스는 갖고 있기때문에, 만료되었다고 바로 원본 서버로부터 새로운 리소스를 받아오는 것이 아니라 서버에 한번 물어보는 과정을 거친 후(조건부 요청), 리소스가 변경되지 않았다면 캐싱된 리소스를 그대로 사용합니다. 보통 변경에 민감한 리소스는 응답헤더에 Cache-Control: max-age=0를 설정합니다. 

Expire

Cache-control:max-age는 유효기간을 지정하는 반면, Expire헤더는 만료 일자를 지정합니다. 

ETag

원본 서버가 리소스를 식별하기 위해 부여하는 고유 번호입니다. ETag는 임의의 문자들이 따옴표 안에 포함되도록 하며, 이 값은  원본서버에서 결정합니다.
캐시서버에서는 조건부 요청이 들어왔을 때 원본 서버의 리소스가 만료되었는지, 캐싱된 리소스를 새로 갱신해야 하는지 여부를 ETag를 이용해 판단합니다. 리소스의 변경이 있다면 200 코드와 함께 변경된 리소스를 함께 보내고, 변경이 없다면 304(not-modified)코드만 본문 없이 보내기 때문에 서버와 네트워크의 자원낭비를 방지할 수 있습니다.
예를들어, "a1b2c3d4e5f6g7h8i9j" 라는 ETag값을 가진 이미지를 웹에서 사용하고 있는데, 해당 이미지가 변경되었는지 검사하기 위해 "이런 ETag 갖고 있는 리소스가 있으면 304주시고, 이런 ETag가 없다면(리소스가 변경되었다는 의미) 200이랑 바뀐 리소스 같이 주세요" 라는 요청을 원본 서버로 보내게 됩니다.  


캐싱은 캐싱 가능한 콘텐츠라면 최대한 많이, 최대한 오래 하는 것이 좋습니다. 웹사이트의 90% 이상이 정적콘텐츠(HTML, CSS, 이미지, javascript)이기 때문에, 정적 콘텐츠의 캐싱만으로 웹의 로딩 속도를 크게 줄일 수 있는데요. www.webpagetest.org 사이트를 통해 얼마나 많은 파일들을 캐시할 수 있는지 확인할 수 있습니다. 

 

댓글