728x90
캐시 기본 동작
- 웹 캐싱이란, 웹 서버 과부하에 의한 웹 트래픽을 감소시키고 사용자가 웹 검색을 할 때 대기시간을 줄이는 기술을 말한다.
- 자주 찾는 웹 사이트나 파일을 따로 캐시(cache)에 저장해 놓고 필요할 경우 해당 사이트까지 직접 찾아가지 않고 임시 저장소에서 수시로 불러낼 수 있다.
- 웹 캐싱은 인터넷 접속 속도를 줄이므로 인터넷 검색 속도를 향상 시킨다.
- 캐싱은 주로 정적인 파일(static file)들을 불러오는데 사용된다.
- 이미지 파일
- CSS 파일
- HTML 파일
- 자바스크립트 파일
🔍 캐시 미적용
- 데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운 받아야 한다.
- 인터넷 네트워크는 매우 느리고 비싸다. 그러므로 비효율적이다.
- 브라우저 로딩 속도가 느려진다.
💡 첫 번째 요청
- 클라이트가 서버에게 star.jpg 이미지 파일을 요청한다.
- 서버는 해당 이미지가 있으면 응답을 해줘야하는데 이미지의 HTTP 헤더 + 바디를 합쳐서 대략 1.1M 용량의 데이터를 응답한다.
- 클라이언트는 해당 이미지를 응답 받아 사용한다.
💡 두 번째 요청
- 클라이언트는 또 다시 서버에게 star.jpg 이미지 파일을 요청한다.
- 서버는 동일한 이미지를 또 1.1M 용량의 데이터를 응답한다.
- 클라이언트는 해당 이미지를 응답 받아 사용한다.
- 동일한 이미지를 요청하는데 네트워크를 통해 같은 데이터를 또 다운 받아야 한다.
- 용량이 클 수록 비용이 커지고 브라우저 로딩속도가 느려진다.
🔍 캐시 적용
💡 첫 번째 요청
- HTTP 응답 헤더에 cache-control 속성을 넣어서 캐시 유효시간을 넣어준다,
- cache-control:max-age=60 → 캐시 유효시간 : 60초
- 그러면 캐시를 사용하기 때문에 응답 결과를 브라우저 캐시에 저장하며 60초간 유효하다.
💡 두 번째 요청 - 캐시 유효
- 두 번째 요청할 때는 캐시를 먼저 조회한다.
- 캐시가 존재하므로 해당 캐시에서 자료를 가져온다.
- 캐시 덕분에 캐시 가능 시간동안 네트워크를 사용하지 않아도 된다.
- 비싼 네트워크 사용량을 줄일 수 있다.
- 브러우저 로딩 속도가 매우 빨라진다.
💡 세 번째 요청 - 캐시 시간 초과
- 캐시 유효 시간이 초과하면, 서버를 통해 데이터를 다시 다운받아 캐시를 업데이트한다.
- 이 때 다시 네트워크 다운로드가 발생한다.
검증 헤더와 조건부 요청 1
- 캐시가 만료된 후에도 서버에서 데이터를 변경하지 않은 경우 서버에서 동일한 데이터를 요청해서 응답 받는 것은 비용 낭비다.
- 이럴 때 저장해 둔 캐시를 재사용할 수 있도록 클라이언트의 데이터와 서버의 데이터가 동일하다는 것을 확인할 방법이 필요하다.
- 그 방법이 검증 헤더와 조건부 요청이다.
- 캐시 유효 시간이 초과해서 서버에 다시 요청하면 두 가지 상황이 존재한다.
- 서버에서 기존 데이터를 변경한 경우 (노란색 별 이미지 →초록색 별 이미지)
- 서버에서 기존 데이터를 변경하지 않은 경우 (노란색 별 이미지 유지)
🔍 검증 헤더 추가
💡 첫 번째 요청
- 데이터가 마지막으로 수정된 시간 정보를 헤더에 작성한다.
- 예) Last-Modified : 2020년 11월 10일 10:00:00
- 실제 웹에서는 UTC 표기법으로 적혀있다.
- 응답 결과를 캐시에 저장할 때 데이터 최종 수정일도 저장된다.
💡 두 번째 요청 - 캐시 시간 초과
- 캐시가 만료되면 다시 요청을 해야하는데 캐시에 최종 수정일 정보(Last-Modified)가 담겨있다면 요청 헤더 중 if-modified-since 에 해당 날짜를 담아서 서버에 보낸다.
- 응답 데이터에 HTTP Body가 없다.
- 상태코드 304 Not Modified 는 기존 캐시 데이터와 변경되는 것이 없다는 것을 의미한다.
- 해당 응답을 받은 클라이언트는 캐시를 갱신하고 다시 일정 시간 동안 유효하게 된다.
🧷 정리
- 캐시 유효 시간이 초과해도, 서버의 데이터가 갱신되지 않으면 서버에서는 메시지 바디 없이 304 Not Modified + 헤더 메타 정보로만 응답한다.
- 클라이언트는 서버가 보낸 응답 헤더 정보를 토대로 캐시 메타 정보를 갱신한다.
- 클라이언트는 캐시에 저장되어 있는 데이터를 재활용한다.
- 결과적으로 네트워크 다운로드가 발생하지만 용량이 적은 헤더 정보만 다운로드 받는다.
검증 헤더와 조건부 요청 2
- 검증 헤더
- 캐시 데이터와 서버 데이터가 같은지 검증하는 데이터다.
- 검증 헤더 2가지
- Last-Modified
- ETag (Entity Tag)
- 조건부 요청 헤더
- 검증 헤더를 조건식으로 사용한 요청 헤더
- If-Modified-Since
- Last-Modified 사용한 것
- If-None-Match
- ETag 사용한 것
- If-Modified-Since
- 조건이 만족하면 200 OK 상태코드로 응답한다. (브라우저 캐시 데이터와 서버 데이터 불일치)
- 조건이 만족하지 않으면 304 Not Modified 상태코드로 응답한다. (브라우저 캐시 데이터와 서버 데이터 일치)
- 검증 헤더를 조건식으로 사용한 요청 헤더
🔍 Last-Modified, If-Modified-Since 단점
- 날짜 기반의 로직을 사용하므로, 데이터 수정 날짜를 기반으로만 데이터 일치/불일치를 판별한다.
- 만약에 서버에서 별도의 캐시 로직을 관리하고 싶을 경우 ETag를 사용할 것
- 예) 데이터가 주석처럼 크게 영향이 없는 요소들을 수정하고 싶은데 캐시를 유지하고 싶은 경우
🔍 ETag (Entity Tag)
- ETag HTTP 응답 헤더는 특정 버전의 리소스를 식별하는 식별자다.
- 서버는 ETag를 HTTP 헤더에 담아 유효 토큰으로 통신한다.
- 유효 토큰은 효율적인 자원 업데이트 체크를 가능하게 한다.
- ETag는 캐시 데이터에 임의의 고유한 버전 이름이 존재한다.
- 예) ETag : "v1.0"
- 데이터가 변경되면 이름을 바꿔서 버전 명을 변경한다. (Hash를 다시 생성한다.)
- 예) ETag : "aaa" → ETag : "bbb"
- 클라이언트는 단순하게 ETag만 보내서 파일 버전이 서로 일치하면 캐시를 유지하고, 일치하지 않으면 서버한테 데이터를 다시 받는다.
💡 데이터 미 변경
- 캐시 : 2020년 11월 10일 10:00:00 vs 서버 : 2020년 11월 10일 10:00:00
- HTTP 응답 메시지에 304 NOT Modified 와 헤더 데이터만 전송한다. (메시지 바디 미포함)
- 응답 데이터 전송 용량은 HTTP 헤더 용량이다.
💡 데이터 변경
- 캐시 : 2020년 11월 10일 10:00:00 vs 서버 : 2022년 3월 1일 12:00:00
- HTTP 응답 메시지에 200 OK 와 모든 데이터를 전송한다. (메시지 바디 포함)
- 응답 데이터 전송 용량은 HTTP 메시지 전체 용량이다. (헤더 + 바디)
💡 ETag 동작
✔ 첫 번째 요청
- 서버는 클라이언트 요청에 응답할 때 헤더에 ETag를 작성해서 응답한다.
- 브라우저 캐시에 ETag를 저장한다.
✔ 두 번쨰 요청 - 캐시 유효 시간 초과
- 클라이언트는 캐시를 먼저 조회하고 유효한 캐시 데이터가 없으면 서버에게 요청을 보낸다.
- 요청을 보낼 때 ETag 버전이 일치하는지 알아보기 위해 헤더에 If-None-Match 조건부 요청 넣는다.
- 브라우저 캐시의 ETag 버전과 서버 Etag 버전이 일치하므로 304 Not Modified 상태코드를 응답 메시지로 보낸다.
- 해당 응답을 받은 클라이언트는 만료된 기존 캐시를 갱신하여 재사용한다.
🧷 정리
- 클라이언트에서 ETag만 서버에 보내서 같으면 캐시를 유지하고, 다르면 데이터를 다시 받는다.
- 캐시 제어 로직을 서버에서 관리한다.
- 클라이언트는 단순히 ETag 값만 서버에 제공하기 때문에 클라이언트는 캐시 매커니즘을 모른다.
- 예) 애플리케이션 배포 주기에 맞춰 ETag를 모두 갱신한다.
🧷 검증 헤더와 조건부 요청 헤더 정리
- 검증 헤더 (Validator)
- ETag
- 예) ETag : "v.10"
- Last-Modified
- 예) Last-Modified : Thu, 04 Jun 2020 07:19:24 GMT
- ETag
- 조건부 요청 헤더
- ETag
- If-Match
- If-None-Match
- Last-Modified
- If-Modified-Since
- If-Unmodified-Since
- ETag
캐시와 조건부 요청 헤더
- 캐시 제어 헤더
- Cache-Control : 캐시 제어
- Pragma : 캐시 제어 (하위호환)
- Expires : 캐시 유효 기간 (하위호환)
🔍 Cache-Control
- 캐시를 제어할 떄 쓰인다.
- 캐시 지시어
- Cache-Control : max-age
- 캐시 유효 시간 설정 (초 단위)
- Cache-Control: no-cache
- 해당 데이터를 캐시해도 되지만, 항상 오리진(origin) 서버에 검증하고 사용한다.
- Cache-Control: no-store
- 데이터에 민감한 정보가 있으므로 저장하면 안된다.
- 메모리에서 사용하고 최대한 빨리 삭제할 것.
- Cache-Control : max-age
🔍 Pragma
- 캐시 제어 헤더지만 잘 안쓰인다.
🔍 Expires
- 캐시 만료일 지정 (초 단위가 아닌 날짜 단위)
- 예) expires: Mon, 01 Jan 1990 00:00:00 GMT
- 캐시 만료일을 정확히 날짜로 지정한다.
- Cache-Control: max-age 방법을 더 권장하므로 Expires는 잘 안쓰인다.
- Cache-Control: max-age 와 Expires가 함께 쓰이면 Expires는 무시된다.
프록시 캐시
- 프록시 서버는 웹 사용자에 의해 빈번히 요청되는 데이터를 사용자와 지리적으로 가까운 웹캐시 서버에 보관해 빠른 서비스를 가능케 한다.
- 그래서 웹 서버를 대신하여 HTTP 요구를 충족시켜준다.
- 또한 저장 디스크를 가지고 있어 최근 호출된 객체의 사본을 저장한다.
🔍 프록시 캐시 도입 전
- 프록시 캐시가 없으면 웹 브라우저가 미국에 있는 ORIGIN 서버에 직접 접근해야하기 때문에 접근 시간이 오래걸린다.
🔍 프록시 캐시 도입
- 한국에 프록시 캐시서버를 두고 한국의 클라이언트는 프록시 캐시 서버를 통해 자료를 가져오도록 한다.
- 여러 사람이 찾는 자료일수록 이미 캐시에 등록되어 있기 때문에 빠른 속도로 자료를 가져올 수 있다.
- 같은 국내에 있기에 ORIGIN 서버에 접근하는 것보다 빠른 속도로 자료를 가져올 수 있다.
- 예) 유튜브에서 고용량 영상을 빨리 볼 수 있는 이유다.
- 클라이언트에서 사용되고 저장되는 캐시를 private 캐시 라고 한다.
- 캐시서버에 캐시를 public캐시 라고 한다.
🔍 Cache-Control
- 캐시 지시어 기타
- Cache-Control : public
- 응답이 public 캐시에 저장되어도 된다는 것을 의미
- Cache-Control : private
- 응답이 해당 사용자만을 위한것임. private 캐시에만 저장한다. (기본값)
- Cache-Control : s-maxage
- 프록시 캐시에만 적용되는 max-age
- 그냥 이런게 있다고 알고만 있으면 된다.
- Age:60 (HTTP 헤더)
- ORIGIN 서버에서 응답 후 프록시 캐시내에 머문 시간 (초)
- 그냥 이런게 있다고 알고만 있으면 된다.
캐시 무효화
Cache-Control : no-cache, no-strore, must-revalidate
Pragma : no-cache
- 캐시 무효화를 확실하게 해야하는 경우 이와 같이 적용하면 된다.
- 캐시를 적용안해도 임의로 캐시로 적용되는 경우가 있다.
- 특정 페이지에서 정말 캐시가 되면 안된다고 할 때 위 내용을 다 넣어주면 된다.
- 예) 통장 잔고
🔍 Cache-Control
- Cache-Control : no-cache
- 데이터는 캐시해도 되지만, 항상 ORIGIN 서버에 검증하고 사용한다.
- Cache-Control : no-store
- 데이터에 민감한 정보가 있으므로 저장하면 안된다.
- 메모리에 사용하고 최대한 빨리 삭제한다.
- Cache-Control : must-revalidate
- 캐시 만료 후 최초 조회시 ORIGIN 서버에 검증한다.
- ORIGIN 서버 접근 실패시 반드시 오류가 발생해야 한다. - 504(Gateway Timeout)
- must-revalidate는 캐시 유효 시간이라면 캐시를 사용한다.
- Pragma : no-cache
- HTTP 1.0 하위호환 버전일 때를 대비하여 캐시 무효화할 때 사용한다.
🔍 no-cache와 must-revalidate를 같이 써야 하는 이유
💡 no-cache 기본 동작
- 캐시 서버 요청을 하면 프록시 캐시 서버에 도착하면 no-cache인 경우 ORIGIN 서버에 요청을 하게된다.
- 그리고 ORIGIN 서버에서 검증 후 응답을 하게 된다.
- 만약에 어떠한 이유라도 프록시 캐시 서버와 서버간 네트워크 연결이 단절되어 접근이 불가능하다면, no-cache에서는 응답이 오류가 아닌 오래된 데이터라도 보여주자는 개념으로 200 OK으로 응답을 한다.
💡 must-revalidate 기본 동작
- 캐시 서버 요청을 해 프록시 캐시 서버로 갔을 때 캐시 서버와 ORIGIN 서버간의 연결이 단절되어 접근이 불가능하다면 must-revalidate에서는 ORIGIN 서버에 접근이 불가능할 경우 항상 오류가 발생해야 한다. (504-Gateway Timeout)
🧷 정리
- 확실한 캐시 무효화 응답으로 작성한 헤더를 사용해야 한다면
- 먼저 no-cache로 무조건 ORIGIN 서버에서 검증을 하게 한다.
- 그리고 must-revalidate로 ORIGIN 서버의 검증이 안되면 오류가 발생하도록 한다.
- 마지막으로 Pragma를 통해 혹시 모를 HTTP 1.0 이하의 버전의 하위호환도 적용하게 한다.
👀 참고자료
https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC/dashboard
https://www.youtube.com/watch?v=c33ojJ7kE7M
https://drive.google.com/file/d/1RLv6bHT5QNc8fRf-8zQFrAYn7l6vLlvJ/view
https://rinae.dev/posts/web-caching-explained-by-buying-milk-kr
728x90
'CS > HTTP' 카테고리의 다른 글
[HTTP] HTTP 헤더1 - 일반 헤더 (0) | 2022.03.02 |
---|---|
[HTTP] HTTP 상태코드 (0) | 2022.03.01 |
[HTTP] HTTP 메서드 (0) | 2022.02.28 |
[HTTP] HTTP 기본 (0) | 2022.02.10 |
[HTTP] 인터넷 네트워크 (0) | 2022.02.09 |