자바생
article thumbnail
728x90

캐시

클라이언트가 서버에 이미지 파일을 요청한다고 생각해보자.

 

캐시가 없을 경우에는 

요청1을 통해 이미지 파일( HTTP헤더, HTTP 바디)을 서버로부터 전송받는다.

요청2를 통해 이미지 파일을 서버로부터 요청1과 같이 전송받는다.

그래서 요청할 때마다 데이터를 다운로드를 받아야하므로 브라우저 로딩 속도가 느려지게 된다.

 

캐시가 있을 경우에는

요청1을 통해 이미지 파일( HTTP헤더, HTTP 바디)을 서버로부터 전송받는다.

서버가 데이터를 전송할 때, 데이터를 브라우저 캐시에 저장한다.

요청2을 통해 이미지 파일을 전송받으려고 할 때, 캐시에 해당 파일이 존재하므로 캐시에서 데이터를 조회한다.

그래서 캐시 덕분에 캐시 가능 시간동안 네트워크를 사용하지 않아도 되므로 브라우저 로딩 속도가 

캐시가 없을 경우보다 빠르게 된다.

 

캐시 시간

캐시가 무한하게 저장이 된다면 그것 또한 문제이다. 그래서 캐시 시간이라는 것이 있다.

캐시 시간이 초과되면 캐시는 삭제가 된다. 이 때 요청을 하게 된다면 다시 서버를 통해 데이터를 요청해야한다.

 


검증 헤더와 조건부 요청

캐시 시간이 초과되어 서버에 다시 요청했을 때 데이터가 변경될 경우, 데이터가 변경되지 않을 경우가 있다.

 

데이터가 변경되지 않을 경우

데이터를 전송하는 대신에 저장해 두었던 캐시를 재사용 할 수 있다.

우리는 데이터가 변경되지 않을 경우를 명시해두고 캐시를 재사용한다고 말할 수 있는 것이다.

그래서 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있어야한다.

 

클라이언트에서 if-modified-since 명령어를 통해 최종 수정일을 서버에게 요청한다.

요청 보낸 수정일과 응답 메시지에 있는 최종 수정일이 같다면, 데이터가 변경되지 않을 경우이므로

서버에서 데이터를 전송할 때, HTTP Body를 전송하지 않고, HTTP 헤더만 전송한다. 이 부분이 정말 중요하다.

캐시에 저장되어 있던 데이터를 재사용할 수 있다. 여기서 응답 메시지는 304 Not Modified를 나타낸다.

수정되지 않았다라는 의미를 뜻한다.

 

검증 헤더

검증 헤더는 앞에서 본 Last-Modified가 있고 ETag라는 것도 있다.

각각의 조건부 요청 헤더는 If-Modified-Since, If-None-Match를 사용한다.

그래서 조건이 만족한다 -> 수정이 됐다라는 말로 200 OK 응답을 받고,

조건을 만족하지 않는다 -> 수정이 안됐다라는 말로 304 Not Modified 응답을 받는다.

이 때, 수정이 안될 시 응답 메시지에는 http body가 없다. http header만 전송한다.

 

단점

만약 a->b로 바뀌고, b->a로 바꼈다고 생각해보자. 

결국엔 수정 날짜가 변경되었으므로, 요청한 데이터가 같아도 다운을 요청하게 된다.

 

위의 단점을 보완하기 위해 ETag를 사용한다.

ETag는 Entity Tag로 캐시용 데이터에 임의의 고유한 버전 이름을 달아둔다.

그래서 처음에 클라이언트가 서버에게 데이터를 요청하고, 서버가 캐시에 저장할 때,

ETag를 사용하여 캐시용 데이터에 별명을 붙인다.

그리고 캐시 시간이 초과되어 클라이언트가 다시 서버에게 데이터를 요청할 때,

If-None-Match를 버전 이름을 이용하여 데이터를 조회한다.

이떄도 위와 같이 수정이 안될 시 http header만 전송한다.

 

 

 

 

그래서 정리하자면

현재 가지고 있는 데이터가 수정 유무를 파악하기 위해 검증 헤더와 조건부 요청 헤더를 이용한다.

검증 헤더에는 Last-Modified와 ETag가 있고, 각각 대응되는 If-Modified-Since, If-None-Match 조건부 요청 헤더가 있다.

Last-Modified는 최신 수정 날짜로 데이터를 판단하고, 

ETag는 데이터가 붙어있는 고유한 이름을 통하여 데이터를 판단한다.

그래서 수정이 됐다면 200 OK 응답을 보내어 데이터를 서버에서 조회하여 새로 받고,

수정이 되지 않았다면 304 Not Modified 응답을 보내어 서버에서는 http 헤더만 전송받는다.

http body는 캐시에 저장되어 있던 데이터를 재사용할 수 있다.

 


캐시와 조건부 요청 헤더

캐시 제어 헤더

캐시 제어 헤더에는 Cache-Control, Pragma, Expires가 있다. Pragma와 Expires는 하위 호환이다.

 

Cache- Control (캐시 지시어)

캐시 지시어에는 

Cache-Control : max-age

-> 캐시 유효 시간, 초 단위

 

Cache-Control : no-cache

-> 데이터는 캐시해도 되지만, 항상 원 서버에 검증하고 사용

 

Cache-Control : no-store

-> 데이터에 민감한 정보가 있으므로 저장하면 안된다.

 

Expires

캐시 만료일을 지정하는 것이다. max-age과 다른 점은 정확한 날짜로 지정한다.

여기서 정확한 날짜로 지정하는 것이 더 좋지 않을까?라고 생각이 들었는데

날짜 지정보다 초 단위가 더 유연하다고 하셨다.

max-age와 함께 사용하면 Expires는 무시된다.

 


프록시 캐시

 

프록시 캐시 도입X
프록시 캐시 도입O

미국 입장에서 사용자에게 응답하는 것이 너무 느리다. 그래서 한국 어딘가에 프록시 캐시 서버를 만들어서

사용자의 요청이 오면 미국에 있는 원 서버로 바로 오는게 아니라 캐시 서버에 들렸다가 온다.

유튜브를 예로 들어보면 사람이 많이 안보는 영상은 로딩 속도가 느리고, 사람들이 많이 본 영상은 빠르다.

 


캐시 무효화

확실한 캐시 무효화 응답

Cache-Control: no-cache, no-store, must-revalidate

각각의 기능은

데이터는 캐시해도 되지만, 항상 원 서버에 검증하고 사용

 

데이터에 민감한 정보가 있으므로 저장하면 안됨

 

캐시 만료후 최초 조회 시 원 서버에 검증해야함

원 서버 접근 실패시 반드시 오류가 발생햐함 - 504(Gateway Timeout)

 

근데 언뜻보면 no-cache와 must-revalidate의 기능이 똑같은 것 같다.

그런데 왜 둘 다 굳이 중복해서 사용할까?

 

한 예를 들어보자.

프록시 캐시 서버에서 no-cache를 보고 아 이건 내가 처리하면 안되겠네하고 원 서버에 요청을 한다.

원 서버에서 검증하고 정상적으로 응답을 한다. 그런데 원 서버에 요청하는 도중에 네트워크 단절이 되어

원 서버에 접근이 불가능한 상황이 생겼다. 여기서 차이가 생긴다

no-cache는 오류보다는 오래된 데이터라도 보여주자라는 옵션을 사용하여 캐시 데이터를 반환할 수 있다.

그래서 200 OK로 응답을 할 수 있다.

 

하지만 must-revalidate는 위와 같은 상황일 때, 무조건 504 Gateway Timeout을 보낸다.

계좌와 관련된 일이라고 생각해보자. 돈을 이체시켰는데 no-cache처럼 옛날 나의 통장 잔고를 보여주면 

당연히 놀라지 않을까? 이러한 점으로 must-revalidate와 no-cache의 차이가 있다.

 


 

 

728x90
profile

자바생

@자바생

틀린 부분이 있다면 댓글 부탁드립니다~😀

검색 태그