티스토리 뷰

해당 글은 김영한님의 모든 개발자를 위한 HTTP 웹 기본 지식 - 인프런 | 강의를 수강하고 정리한 게시글입니다.

캐시 기본 동작

캐시(cache, 문화어 : 캐쉬는 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다. 캐시는 캐시의 접근 시간에 비해 원래 데이터를 접근하는 시간이 오래 걸리는 경우나 값을 다시 계산하는 시간을 절약하고 싶은 경우에 사용한다. 캐시에 데이터를 미리 복사해 놓으면 계산이나 접근 시간 없이 더 빠른 속도로 데이터에 접근할 수 있다.

참고:
캐시 - 위키백과, 우리 모두의 백과사전

 

캐시의 기본 동작을 알기 위해 캐시가 없을 때와 있을 때의 예시를 알아보자

캐시가 없을 때

캐시가 없을 때 브라우저에서 star.jpg를 서버에 여러번 요청한다고 가정하자.

 

[첫번째 요청]


처음 브라우저가 서버에 이미지를 요구하면 1.1M의 이미지를 받게 된다.

 

[두번째 요청]


두번째로 브라우저가 같은 이미지를 서버에 요청해도 1.1M의 이미지를 서버에서 받게된다.

이렇게 캐시가 없다면 데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운로드 받아야한다.

 

[단점]

 

  • 인터넷 네트워크는 매우 느리고 비싸다.
  • 브라우저 로딩 속도가 느려진다.
  • 사용자 입장에서 느린 경험을 받게된다.

 

캐시가 적용되었을 때

이번에도 마찬가지로 캐시가 적용되었을 때 브라우저에서 star.jpg를 서버에 여러번 요청한다고 가정하자.

 

[첫번째 요청]


처음 브라우저가 서버에 이미지를 요구하면 1.1M의 이미지를 브라우저 캐시에 저장한다.(cache-control은 조금있다 다룰 캐시 제어 헤더이다.(캐시가 유효한 시간을 의미))

 

[두번째 요청]


두번째 요청을 하게되면 캐시 유효 시간 검증을 하고 유효하다면 캐시에서 조회에서 브라우저에 가져오게 된다.

 

[장점]

 

  • 캐시 덕분에 캐시 가능 시간동안 네트워크를 사용하지 않아도 된다.
  • 비싼 네트워크 사용량을 줄일 수 있다.
  • 브라우저 로딩 속도가 매우 빠르다.
  • 사용자 입장에서 빠른 경험을 받게된다.

 

이때 만약 캐시 가능 시간을 초과한다면?

 

[세번째 요청]


세번째 요청시 캐시 유효시간을 초과한다면 다시 서버에 이미지를 요구해서 다운받게 된다. 즉, 캐시 유효 시간이 초과하면, 서버를 통해 데이터를 다시 조회하고, 캐시를 갱신하며 이때 다시 네트워크 다운로드가 발생한다.

 

여기서, “캐시 가능 시간을 초과하더라도 다운 받으려는 이미지가 변경되지 않았다면 그대로 사용해도 되는 것 아닐까?”라는 의문이 들 수 있다. 이에 대해 이제 알아보자.

검증 헤더와 조건부 요청1

위의 의문점에서 캐시 유효시간이 초과했을 때 두가지 상황을 고려해볼 수 있다.

 

  1. 서버에서 기존 데이터를 변경하지 않는다.
  2. 서버에서 기존 데이터를 변경한다.

1번의 경우 저장해 두었던 캐시를 재사용 할 수 있다.
단, 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있는 방법이 필요하다.

검증 헤더 추가

클라이언트의 데이터와 서버의 데이터의 동일성을 확인하기 위해 데이터가 마지막에 수전된 시간(Last-Modified)를 헤더에 추가한다.

 

[첫번째 요청]


첫번째 요청으로 브라우저에서 서버에게 이미지를 요청하면 최종 수정일 헤더를 붙여서 이미지를 받게 된다.

 

[두번째 요청]


두번째 요청에서 브라우저 캐시를 확인해서 캐시시간이 초과되었다면, 캐시에 있는 이미지의 최종 수정일 헤더를 서버에 같이 보내게 된다, 그 후 서버의 최종 수정일과 비교하게 된다.

 


그 후 서버에서 상태 코드 “304 Not Midfied” 를 보내주고(이때, HTTP Body는 없다.) 브라우저 캐시에서 이미지를 재사용하게 된다.

 

[정리]

 

  • 캐시 유효 시간이 초과해도, 서버의 데이터가 갱신되지 않으면 304 + 헤더 메타 정보만 응답한다(바디 X).
  • 클라이언트는 서버가 보낸 응답 헤더 정보로 캐시의 메타 정보를 갱신한다.
  • 클라이언트는 캐시에 저장되어 있는 데이터를 재활용한다.
  • 결과적으로 네트워크 다운로드가 발생하지만 용량이 적은 헤더 정보만 다운로드한다.
  • 매우 실용적!

 

검증 헤더와 조건부 요청2

위에서는 2번째 요청에서 캐시에 있는 데이터가 수정이 안되었을 경우를 다뤘는데, 만약 데이터가 수정 되었다면 어떻게 되는지를 알아보자.

 

[데이터 변경 예시]

 

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

 

[데이터 미변경 예시]

 

  • 캐시 : 2020년 11월 10일 10:00:00 VS 서버: 2020년 11월 10일 10:00:00
  • 304 Not Modified, 헤더 데이터 전송(BODY 미포함)
  • 전송 용량 0.1M(헤더 0.1M, 바디 1.0M(미포함))

 

데이터 변경 예시에서 보다시피 다시 데이터를 전송한다.

그러나, 만약 수정해서 날짜가 바뀌었지만, 데이터의 결과가 똑같다면?(A -> B, B -> A로 다시 변경한 경우) 데이터를 굳이 다시 보내야할까? 이런 의문이 들 수있다. 이제 이런 단점들을 알아보고 해결방법을 알아보자.

 

[Last-Modified, If-Modified-Since 단점]

 

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

 

이럴 경우 사용되는게 ETag(Entity Tag)이다. ETag는 캐시용 데이터에 임의의 고유한 버전 이름을 달아둔다.(사용자가 정의)
예시) ETag: “aaaa”, Etag: “a2sdfsdf” 등

 

데이터가 변경되면 이 이름을 바꾸어서 변경하면 된다.(데이터를 기반으로 Hash를 다시 생성해서 사용)
예시) ETag: “aaaa” -> Etag: “bbbb”


단순하게 ETag만 보내서 같으면 유지, 다르면 다시 받기를 하면 되는 것이다.

 

아래는 그 예시를 그림으로 나타낸 것이다.

 

[첫번째 요청]


첫번째 요청에서 응답으로 ETag와 이미지를 받고 응답 결과를 브라우저 캐시에 저장하게 된다.

 

[두번째 요청]


두번째 요청에서 캐시 유효 시간이 초과 되었다면 서버에 ETag를 보내 이미지를 요청하게 된다.

 


그후 서버에서 ETag를 확인해 데이터가 수정되지 않았다면 상태 코드 “304 Not Midfied” 를 보내주고(이때, HTTP Body는 없다.) 브라우저 캐시에서 이미지를 재사용하게 된다. (헤더 데이터도 갱신)

 

[정리]

 

  • 단순하게 ETag만 서버에 보내서 같으면 유지, 다르면 다시 받기.
  • 캐시 제어 로직을 서버에서 완전히 관리한다.
  • 클라이언트는 단순히 이 값을 서버에 제공하면 된다.(클라이언트는 캐시 메커니즘을 모름)

 

캐시와 조건부 요청 헤더

이번에는 캐시와 관련된 제어 헤더와 조건부 요청에 관련된 헤더에 대해 알아보자.

 

캐시 제어관련 헤더

Cache-Control

Cache-Control은 요청과 응답 내의 캐싱 메커니즘을 지시하기 위해 사용된다.

대표적인 방법들은 다음과 같다.

 

[예시]

Cache-Control: max-age
캐시 유효 시간, 초 단위 설정

 

Cache-Control: no-cache
데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증(조건부 요청헤더를 통해)하고 사용한다. (원서버는 중간 프록시 서버가 아닌 진짜 서버를 의미하고 이는 뒤에서 자세히 다룰예정)

 

Cache-Control: no-store
데이터에 민감한 정보가 있으므로 저장하면 안된다.
(메모리에서 사용하고 최대한 빨리 삭제)

 

Pragma

Pragma는 캐싱 매커니즘을 지시하기위해 사용되는 헤더이나 HTTP 1.0 하위 호환을 위해 사용되고 잘 사용되지 않는다.

 

[예시]
Pragma: no-cache

 

Expires

Expires는 캐시 만료일을 지정할 수 있는 헤더이고 이것 또한 HTTP 1.0 하위 호환을 위해 사용되고 잘 사용되지 않는다. (Cahce-Control의 max-age를 설정하면 초단위로 할 수 있기때문에 더 유연하게 설계할 수 있다.)

 

[예시]
expires: Mon, 01 Jan 1990 00:00:00 GMT

참고: Cache-Control: max-age와 함께 사용하면 Expires는 무시된다.

 

 

조건부 요청 관련 헤더

조건부 요청 관련헤더는 위에서 다뤘던 ETag와 Last-Modified를 사용한다.

 

[검증 헤더 (Validator)]

 

  • ETag: “v1.0”, Etag: “a2sdfsdf
  • Last-Modified: Thu, 04 Jun 2020 07:19:24 GMT

 

[조건부 요청 헤더]

 

  • if-Match, If-None-Match: ETag 값을 사용한다.
  • If-Modified-Since, If-Unmodified-Since: Last-Modified 값을 사용한다.

 

프록시 캐시

프록시 캐시는 웹 사용자에 의해 많은 요청이 있는 데이터를 사용자와 가까운 웹 캐시 서버에 보관해서 빠른 서비스를 가능하게하는 기술을 의미한다.(유튜브를 생각해보면 외국 영상이라도 사람들이 많이 보는 영상은 빠르고 잘 보지않는 영상은 느릴 수 있다.)

 

[프록시 캐시 도입 전]


프록시 캐시를 사용하기 전에는 클라이언트가 데이터를 요청하면 0.5초 걸리지만

 

[프록시 캐시 도입 후]


프록시 캐시를 사용한 후에는 클라이언트가 데이터를 요청하면 0.1초만에 받아 볼 수 있다. (처음 데이터를 요청한 사용자는 느리다.)

참고: 여기서, public 캐시는 공용으로 사용하는 데이터를 가리키고 private 캐시는 자신의 웹 브라우저나 로컬에 저장되는 캐시를 의미한다. (사용자 정보같은 경우는 공용으로 캐시되면 안되기 때문에)

 

[관련된 Cache-Control 헤더의 옵션들]

 

Cache-Control: public
- 응답이 public 캐시에 저장되어도 됨

Cache-Control: private
- 응답이 해당 사용자만을 위한 것임, private 캐시에 저장해야 함(기본값)

Cache-Control: s-maxage
- 프록시 캐시에만 적용되는 max-age

Age: 60**(HTTP 헤더)
- 오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간(초)

 

캐시 무효화

캐시를 적용 안해도 웹브라우저들이 GET요청의 경우 임의로 캐시를 해버리는 경우가 있다. 그러나, 정말로 캐시가 되면 안되는 정보들(사용자 정보, 사용자 통장잔고등)이 있다. 이런 경우 어떻게 해야하는지 알아보자.

 

[확실한 캐시 무효화 응답}
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache(HTTP 1.0 예전 버전에서 요청이 올 수 있기 때문에)

 

위의 옵션들을 다 넣어주면 확실하게 대응해 줄 수 있다. 위의 옵션들의 의미는 다음과 같다.

 

  • Cache-Control: no-cache
    • 데이터는 캐시해도 되지만, 항상 원 서버에 검증하고 사용(이름에 주의!)
  • Cache-Control: no-store
    • 데이터에 민감한 정보가 있으므로 저장하면 안됨(메모리에서 사용하고 최대한 빨리 삭제)
  • Cache-Control: must-revalidate
    • 캐시 만료후 최초 조회시 원 서버에 검증해야함
    • 원 서버 접근 실패시 반드시 오류가 발생해야함 - 504(Gateway Timeout)
    • must-revalidate는 캐시 유효 시간이라면 캐시를 사용함
  • Pragma: no-cache
    • HTTP 1.0 하위 호환

 

이번에는 no-cache와 must-revalidate의 기본 동작에대해 간단히 알아보자.

 

[no-cache 기본 동작 1]

 

  • 기존 브라우저 캐시에 사용하려는 데이터가 “no-cache”가 붙어있으면 서버에 요청할 때 no-cache를 ETag와 함께 보내게 된다.
  • 프록시 캐시 서버에서 이를 받으면 no-cache를 보고 원서버에 보낸다.
  • 원서버에서 데이터를 검증을하고 데이터 변경이 없으면 “304 Not Modified“를 보내준다.
  • 그 후 브라우저에서 응답받으면 캐시데이터를 사용한다.

 

[no-cache 기본 동작 2]


그런데 만약, 프록시 캐시 서버에서 원 서버로 네트워크가 단절되어 원 서버에 접근이 불가능한 상황일때, 프록시 캐시 서버 설정에 따라 오류를 내지않고 오래된 데이터를 보낼 수 있다. 이를 해결하기 위한 옵션이 must-revalidate이다.

 

[must-revalidate 기본 동작]


no-cache 기본 동작 2와 같은 상황이 벌어졌을 때 must-revalidate 옵션은 504 에러를 발생하게 된다.

 

 

이렇게 HTTP 헤더와 관련된 것들을 정리해봤고 조금 더 자세한 내용은 아래를 참고해보자.

참고:
RFC 7230~7235: RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함