Post

캐시와 조건부 요청

캐시란?

캐시(cache)는 컴퓨터 과학에서 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다.

같은 데이터에 반복적으로 엑세스하는 경우나 잘 변하지 않는 데이터의 경우 캐시를 사용하면 더 빠른 속도로 데이터에 접근할 수 있다. 그래서 데이터의 재사용 횟수가 한 번 이상이어야 캐시는 의미가 있다.


여러가지 캐시의 종류

  • CPU 캐시

  • 디스크 캐시

  • 웹 캐시: 브라우저 캐시, 프록시 캐시


이번 포스팅에서는 웹 캐시를 정리하고자 한다.

캐시의 기본 정의에 따라 웹 캐시는 웹 페이지의 요소를 저장하기 위한 임시 저장소이다.

HTTP 요청으로 가져올 수 있는 모든 종류의 리소스(HTML, CSS, JS, 이미지, 비디오 파일)를 로컬 브라우저 내부나 근처에 있는 프록시 서버에 임시 저장하여 사용자가 동일한 서버로 다시 요청할 때, 원 서버와의 연결없이 데이터를 캐시에서 빠르게 가져올 수 있다.

서버는 HTTP 헤더에 캐시 유효 시간을 설정하여 클라이언트에 응답하고, 브라우저는 응답 결과를 캐시에 저장한다. 2번째 요청 시 브라우저 캐시를 먼저 조회하여 캐시 유효 시간 내에 있으면 브라우저 내 캐시에서 데이터를 가져온다.




캐시 기본 동작

캐시 적용 X

image image
image image
  • 데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운로드 받아야 한다.

  • 인터넷 네트워크는 매우 느리고 비싸다.

  • 브라우저 로딩 속도가 느리다.

  • 느린 사용자 경험


캐시 적용 O - 캐시 시간 이내

image image
image image
  • 최초 이후에는 start.jpg를 cache-control(캐시 유효 시간) 동안 다시 다운받지 않아도 됨.

  • 캐시 덕분에 캐시 가능 시간동안 네트워크를 사용하지 않아도 됨.

  • 브라우저 로딩 속도가 매우 빠름

  • 빠른 사용자 경험


캐시 적용 O - 캐시 시간 초과

image image
image
  • cache-control(캐시 유효 시간)이 지나면 start.jpg를 다시 요청(서버와 캐시의 데이터가 일치하지 않을 수도 있기 때문)

  • 새로 응답받은 응답 결과를 캐시에 갱신

  • 캐시 유효 시간이 초과하면, 서버를 통해 데이터 다시 조회하고, 캐시 갱신


위의 예시에서 start.jpg가 변하지 않았지만 캐시 유효 시간이 지나면 다시 다운받아야하는 문제가 발생한다.

데이터가 변했는지 확인 후 변했을 경우에만 다운받으면 좋겠다는 생각을 할 것이다. 이것을 구현하도록 도와주는게 검증 헤더와 조건부 요청이다.




검증 헤더와 조건부 요청

검증 헤더

  • 캐시 데이터와 서버 데이터가 같은지 검증하는 데이터
  • Last-Modified , ETag

조건부 요청 헤더

  • 검증 헤더로 조건에 따른 분기
  • If-Modified-Since: Last-Modified 사용
  • If-None-Match: ETag 사용
  • 조건이 만족하면 200 OK
  • 조건이 만족하지 않으면 304 Not Modified


검증 헤더 - Last-Modified

캐시 시간 초과 시 발생할 수 있는 상황

  • 서버에서 기존 데이터를 변경하지 않음
  • 서버에서 기존 데이터를 변경 => 검증 헤더와 조건부 요청으로 서버의 데이터가 같은지 다른지 확인

서버에서 기존 데이터를 변경하지 않음 - 첫 번째 요청

image image
  • 서버의 응답헤더에 Last-Modified(검증 헤더)로 데이터가 마지막 수정된 시간을 알려줌

  • 브라우저 캐시에 데이터가 마지막 수정된 시간이 포함된 응답 결과를 저장


서버에서 기존 데이터를 변경하지 않음 - 두 번째 요청(캐시 시간 초과)

image image
image image
  • 브라우저 캐시에 있던 데이터 마지막 수정 시간을 if-modified-since(조건부 요청)으로 보냄

  • 서버에서 데이터 최종 수정일과 요청에서 온 데이터 마지막 수정 시간을 비교에 검증


image image
  • HTTP Body를 제외하고 헤더부분만 응답으로 보내줌

  • 304 Not Modified로 응답 결과를 재사용하고, 헤더 데이터를 갱신

image


  • 캐시 유효 시간이 초과해도, 서버의 데이터가 갱신되지 않으면

  • 304 Not Modified + 헤더 메타 정보만 응답(바디 X)

  • 클라이언트는 서버가 보낸 응답 헤더 정보로 캐시의 메타 정보 갱신

  • 클라이언트는 캐시에 저장되어 있는 데이터 재활용

  • 네트워크 다운로드가 발생하지만 용량이 적은 헤더 정보만 다운로드

  • 매우 실용적인 해결책


서버에서 기존 데이터를 변경

만약 if-modified-since 이후에 데이터가 수정되었으면?


  • 데이터 변경 예시

    • 캐시: 2020년 11월 10일 10:00:00 vs 서버: 2020년 11월 10일 11:00:00
    • 200 OK, 모든 데이터 전송(BODY 포함)
    • 전송 용량 1.1M (헤더 0.1M, 바디 1.0M)


  • Last-Modified, If-Modified-Since 단점
    • 1초 미만 단위로 캐시 조정 불가능
    • 날짜 기반의 로직 사용
    • 데이터를 수정해서 날짜가 다르지만, 같은 데이터를 수정해서 데이터의 결과가 똑같은 경우
    • 서버에서 별도의 캐시 로직을 관리하고 싶은 경우 => ETag 사용 ex) 스페이스나 주석처럼 크게 영향이 없는 변경에서 캐시를 유지하고 싶은 경우



검증 헤더 - ETag(Entity Tag)

  • 캐시용 데이터에 임의의 고유한 버전 이름을 달아둠

  • 데이터가 변경되면 이 이름을 바꾸어서 변경(Hash 다시 생성) 예) ETag: “v1.0”, ETag: “a2jiodwjekjl3”

  • ETag를 보내서 같으면 유지, 다르면 다시 받기 예) ETag: “aaaaa” -> ETag: “bbbbb”

첫 번째 요청

image image
  • 서버에서 클라이언트로 검증 헤더(ETag) 전달

  • 브라우저 캐시에 응답 결과를 캐시에 저장


두 번째 요청 - 캐시 시간 초과

image image
image image
  • 클라이언트에서 캐시가 가지고 있는 ETag를 조건부 요청(If-None-Match)으로 보냄


image image
  • 서버에서 ETag의 값과 캐시의 값을 비교 후 같으면(데이터가 변경되지 않을 경우) 304 Not Modify


image image


  • 특징
    • 진짜 단순하게 ETag만 서버에 보내서 같으면 유지, 다르면 다시 받기!
    • 캐시 제어 로직응 서버에서 완전히 관리
    • 클라이언트는 캐시 메커니즘을 모름




캐시와 조건부 요청 헤더

Cache-Control: 캐시 제어

  • max-age: 캐시 유효 시간, 초단위

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

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

  • public: 응답이 public 캐시에 저장되어도 됨

  • private: 응답이 해당 사용자만을 위한 것(로그인), private 캐시에 저장해야 함(기본값)

  • must-revalidate: 캐시 만료후 최초 조회시 원 서버에 검증해야함


Pragma: 캐시 제어(하위 호환)

  • Pragma: no-cache

  • HTTP 1.0 하위 호환


Expires: 캐시 유효 기간(하위 호환)

  • expires: Mon, 01 Jan 1990 00:00:00 GMT

  • 캐시 만료일을 정확한 날짜로 지정

  • HTTP 1.0 부터 사용

  • 지금은 더 유연한 Cache-Control: max-age 권장

  • Cache-Control: max-age와 함께 사용하면 Expires는 무시




프록시 캐시

프록시 캐시란 클라이언트와 서버 사이에 위치하는 중간 서버로, 클라이언트의 요청을 대신한다.

서버로부터 데이터를 가져오고, 그 결과를 저장해 두었다가 동일한 요청이 다시 발생할 경우 저장해 둔 데이터를 제공함으로써 응답 시간을 단축시키고 서버의 부하를 줄이는 역할을 한다.


원 서버(origin server) 직접 접근

image

  • 이미지 하나 다운받는데에 0.5초씩 다 기다려야함

  • 사용자가 기다리는 시간이 많음


프록시 캐시 도입

image

  • 도메인에 접근하면 원 서버로 가는것이 아니라 프록시 캐시 서버를 거쳐서 이동

  • 첫 번째 유저는 프록시 서버에서 미국의 원 서버의 응답을 받고 받아 조금 느릴 수 있음

  • 두 번째 유저 부터는 프록시 서버의 캐시된 데이터를 받아와 빠르게 응답받을 수 있음

image

  • 로컬 웹 브라우저: private캐시

  • 프록시 캐시 서버: public 캐시




캐시 무효화

  • 캐시를 적용안해도 웹 브라우저가 GET요청인 경우 임의로 캐시 하기도 함.

  • 캐시를 정말 해서는 안되는 페이지에서는 캐시 무효화를 해주어야 함.


Cache-Control

  • Cache-Control: no-cache

    • 데이터는 캐시해도 되지만, 항상 원 서버에 검증하고 사용
  • Cache-Control: no-store

    • 데이터에 민감한 정보가 있으므로 저장하면 안됨
  • Cache-Control: must-revalidate

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


no-cache vs must-revalidate

no-cache

image image
image

프록시 캐시에서 원 서버에 요청을 해야하는데 네트워크가 단절되었을 때, 프록시 서버에서 이전의 데이터를 보여주는 설정을 하기도함.

그러면 원 서버의 응답이 아니라 프록시 서버의 응답이 되는 것


must-revalidate

image

위와 같은 상황일 때, 무조건 504 Getway Timeout 이라는 오류 발생

ex) 통장잔고 내역을 보여주어야 하는데 원 서버와 프록시 서버의 네트워크 문제로 프록시 서버에서 옛날 데이터를 보여주면 큰 문제! 그럴때는 must-revalidate 사용해주어야함




📑 참고 자료

인프런: 모든 개발자를 위한 HTTP웹 기본 지식

캐시와 조건부 요청

This post is licensed under CC BY 4.0 by the author.