캐시(Cache)는 어떤 데이터를 한번 받아온 후, 원 저장소보다 가까운 곳에 일정 시간 저장하여 필요시 더 빠르게 불러와서 사용하는 프로세스를 의미한다. 클라이언트는 HTTP 요청을 통해 서버로부터 필요한 리소스를 불러온다.
만약 같은 리소스를 반복해서 불러온다면 캐싱을 적용해 볼 수 있다. 클라이언트 애플리케이션에 의해 내부 디스크에서 이루어지는 캐시를 '브라우저 캐시'라고 하며, 'HTTP 캐시'라고 불리기도 한다.
브라우저 캐싱을 처리하는 속성에는 Cache-Control, Etag, Pragma, Expires 등이 있다.
( Pragma, Expires는 하위 호환을 위한 속성으로 권장되지 않는다. )
① 클라이언트에서 hello.jpg 이미지를 요청한다.
② 서버에서 HTTP 헤더 + 바디를 합쳐 1.1M 용량의 데이터를 응답한다.
③ 클라이언트에서 해당 이미지를 받아 사용한다.
④ 클라이언트에서 다시 한번 hello.jpg 이미지를 요청한다.
⑤ 서버에서는 동일한 이미지(1.1M 용량)의 데이터를 응답한다.
캐시가 없을 경우, 매번 같은 용량의 데이터를 주고 받기 때문에 낭비가 심하고 로딩속도가 느려지게 된다.
① 클라이언트에서 hello.jpg 이미지를 요청한다.
② 서버에서 HTTP 헤더 + 바디를 합쳐 1.1M 용량의 데이터를 응답한다.
cahce-control: max-age=60
넣어주어 60초 동안 캐시가 유효하다고 알려준다. ③ 클라이언트에서 cache-control
값을 이해하고 웹브라우저 캐시에 60초 동안 이미지를 저장한다.
④ 클라이언트에서 다시 한번 hello.jpg 이미지를 요청한다. 이때 서버가 아닌 브라우저 캐시를 우선 조회한다.
⑤ 만일 캐시 되어있고 60초 이내에 요청한 상태라면, 브라우저 캐시에서 이미지를 가져온다.
이렇게 브라우저 캐시에서 데이터를 가져오면 불필요한 네트워크 다운로드를 효과적으로 줄일 수 있게 된다. max-age
값을 사용하여 캐시가 유효한 기간을 지정할 수 있는데, 만약 캐시 유효 시간이 지나면 어떻게 될까?
⑥ 클라이언트가 브라우저 캐시에 hello.jpg 이미지를 요청했지만, 60초 유효시간이 초과되어 가져올 수 없다.
⑦ 클라이언트는 다시 서버에게 처음과 같이 요청하게 된다.
⑧ 서버는 다시 Response Header에 cahce-control: max-age=60
넣어 응답한다.
⑨ 브라우저는 이미지를 60초 동안 캐시에 다시 저장한다.
이런 경우 캐시 유효 시간을 늘리는게 좋지 않을까? 생각할 수도 있다. 그러나 데이터 중에는 자주 변경되는 데이터가 있기 때문에 유효 시간을 늘리는 것은 오래된 데이터를 응답 받을 수 있다.
따라서 캐시 유효 시간은 지났지만, 변경되지 않은 데이터를 위한 '캐시 검증 로직'을 수행할 수 있다.
캐시 만료 후에도 서버에서 리소스를 수정하지 않은 경우 서버에서 동일한 데이터를 응답받는 것은 효율적이지 못한 방법이다. 이럴 경우 저장해둔 웹브라우저 캐시를 사용할 수 있으면 좋을 것 같은데 이를 위해 HTTP에서는 검증 헤더를 통해 처리할 수 있다.
Last-Modified: Wed, 11 Dec 2023 17:47:21 GMT
서버가 클라이언트에게 응답할 때 HTTP 헤더에 넣는 값
데이터의 최종 수정 시각을 명시
If-Modified-Since: Wed, 11 Dec 2023 17:47:21 GMT
클라이언트가 서버에 요청할 때 HTTP 헤더에 넣는 값
캐시 데이터의 Last-Modified 값이 들어감
- 캐시에 있는 수정 시각과 서버에 있는 수정 시각이 같으면 304 Not Modified 응답 > 캐시 재사용
- 캐시에 있는 수정 시각과 서버에 있는 수정 시각이 다르면 200 OK 응답 > 새로운 데이터 전송
① 클라이언트에서 hello.jpg 이미지를 요청한다.
② 서버는 cache-control: max-age=60
과 추가적으로 Last-Modified: Wed, 11 Dec 2023 17:47:21 GMT
응답 헤더를 통해 리소스의 마지막 수정 시간 정보를 넣어 응답한다.
③ 클라이언트에서 응답 데이터와 데이터 최종 수정일을 캐시에 저장한다.
④ 100초가 지난 후(캐시 유효시간 초과), 클라이언트는 hello.jpg 이미지를 다시 요청한다.
if-modified-since: Wed, 11 Dec 2023 17:47:21 GMT
를 요청 헤더에 담아 서버에 보낸다.⑤ 서버는 수정일을 비교하여 수정일이 같을 경우 304 Not Modified 상태코드로 응답한다. (헤더에 대한 용량만 전송된다.)
⑥ 304 응답을 받은 클라이언트는 리소스 수정이 없음을 감지하고 브라우저 캐시에서 리소스를 가져오고 캐시 유효 시간을 갱신한다.
① 1초 미만 단위로 캐시 조정이 불가능하다.
② 리소스 내용을 A에서 B로 수정하고, 다시 롤백한 경우 캐시 내용은 같지만 수정 날짜가 변경되어 다시 네트워크에서 다운로드 해야 한다.
③ 서버에서 관리하고 싶은 경우 한계가 있다.
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
서버가 클라이언트에게 응답할 때 HTTP 헤더에 넣는 값
특정 버전의 리소스를 식별하는 고유 식별자
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
클라이언트가 서버에 요청할 때 HTTP 헤더에 넣는 값
캐시 데이터의 ETag 값이 들어감
- 캐시에 있는 ETag와 서버에 있는 ETag가 같으면 304 Not Modified 응답 > 캐시 재사용
- 캐시에 있는 ETag와 서버에 있는 ETag가 다르면 200 OK 응답 > 새로운 데이터 전송
① 클라이언트에서 hello.jpg 이미지를 요청한다.
② 서버는 cache-control: max-age=60
과 추가적으로 ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
응답 헤더에 넣어 이미지와 함께 응답한다.
③ 클라이언트에서 응답 데이터와 ETag 값을 캐시에 저장한다.
④ 100초가 지난 후(캐시 유효시간 초과), 클라이언트는 hello.jpg 이미지를 다시 요청한다.
if-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
를 요청 헤더에 담아 서버에 보낸다.⑤ 서버는 ETag 값을 비교하여 같을 경우 304 Not Modified 상태코드로 응답한다. (헤더에 대한 용량만 전송된다.)
⑥ 304 응답을 받은 클라이언트는 리소스 수정이 없음을 감지하고 브라우저 캐시에서 리소스를 가져오고 캐시 유효 시간을 갱신한다.
웹 캐시에는 브라우저 캐시와 프록시 캐시(Proxy Cache)가 있다. 프록시란 클라이언트와 본서버를 중계하는 중간에 위치한 서버 대리자로서, 클라이언트의 요청을 대신 받고 본서버에 전해주는 역할을 한다.
이 프록시를 캐시 서버로 이용할 수 있다.
예를 들어, 우리가 구글에 접속하는 경우 외국 서버에 직접 접근하여 이미지를 가져온다면 상당한 시간이 걸릴 것이다. 이때 한국에 프록시 캐시 서버를 두고, 최초 요청만 외국 서버에서 가져온 후 캐시 서버에 저장하면 빠른 속도로 자료를 가져올 수 있다.
프록시 캐시도 브라우저 캐시 처럼 HTTP 헤더에 Cache-Control
을 설정해야 한다.
( 클라이언트에 저장되는 캐시를 private 캐시
프록시 캐시 서버의 캐시를 public 캐시
라고 한다. )
Cache-Control: public
: 응답이 public 캐시에 저장되어도 된다.Cache-Control: x-maxage
: 프록시 캐시에서 사용되는 max-age 값프록시 캐시의 경우 '캐시 무효화'에 대해 알아두어야 한다. 클라이언트의 의도와 상관없이 웹 브라우저가 임의로 캐싱하여 업데이트가 되지 않는 문제가 발생할 수 있는데, 이럴 경우 캐시를 무효화해야 한다.
캐시 무효화(Cache Busting)은 웹 브라우저의 캐시를 완전히 제거해버리는 것을 말한다.
Cache-Control: no-cache, no-store, must-revalidate
Cache-Control: no-cache
: 데이터는 캐시해도 되지만 항상 원 서버에 검증하고 사용한다. (=max-age=0
)Cache-Control: no-store
: 데이터에 민감한 정보가 있어 저장하면 안된다.Cache-Control: must-revalidate
: 캐시 만료 후 최초 조회 시, 원 서버에 검증해야 할때 설정한다.캐시 무효화 헤더를 설정할 때, no-cache와 must-revalidate를 같이 설정한다. must-revalidate는 no-cahce에 의해 원 서버에 검증 요청을 보내는 도중 원서버와 프록시 캐시 서버의 연결이 끊어져 검증이 불가할 경우, 504 Gateway Timeout
오류를 발생시켜준다.
만약 must-revalidate를 설정하지 않은 경우, no-cache에 의해 오래된 데이터라도 보여주자라는 개념으로 200 OK로 응답하게 된다. 따라서 must-revalidate를 통해 프록시 캐시 서버가 자체적으로 캐시 데이터를 반환하는 경우를 사전 차단한다.
CDN(Content Delivery Network)은 세계 곳곳에 있는 데이터 센터에 콘텐츠를 저장두고 요청 받으면 지리적으로 가장 가까운 데이터 센터에서 콘텐츠를 제공하는 방식이다.
CDN은 각 지역의 유저 요청에 따라 원 서버가 아닌 다른 서버로 가도록분산시키는 역할을 하며, 이 과정에서 캐싱이 사용된다.
간단히 말하면, 프록시 캐시 서버는 주로 내부 네트워크에서 사용되며 동적 콘텐츠를 다루기 위한 것이며, CDN은 전 세계적으로 분산된 위치에서 정적 콘텐츠를 빠르게 서빙하기 위한 것이다.