캐시
캐시(cache, 문화어: 캐쉬, 고속완충기, 고속완충기억기)는 컴퓨터 과학에서 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다. 캐시는 캐시의 접근 시간에 비해 원래 데이터를 접근하는 시간이 오래 걸리는 경우나 값을 다시 계산하는 시간을 절약하고 싶은 경우에 사용한다. 캐시에 데이터를 미리 복사해 놓으면 계산이나 접근 시간없이 더 빠른 속도로 데이터에 접근할 수 있다.
캐시는 시스템의 효율성을 위해 여러 분야에서 두루 쓰이고 있다.
웹 개발에서의 캐시는 주로 서버에서 반복적으로 동일한 요청을 받아서 결과를 돌려주어야 할 때(이미지, 썸네일 등)나 접근 시간에 비해 원래 데이터에 접근하는 시간이 오래걸리는 경우에 사용을 하게 된다. 혹은 Web Client Cache처럼 클라이언트의 웹 브라우저에서 사용되는 캐시도 존재한다. 클라이언트가 자주 들어가는 사이트의 이미지나 데이터들을 캐시로 저장하고 있다면 인터넷을 통해 다시 받아오지 않아도 빠르게 사용이 가능하다.
이렇게 Cache에 접근함으로써 Original 데이터에 접근하여 검색하는 시간을 절약할 수 있게 되므로 탐색에 들어가는 에너지와 시간, 자원들을 아낄 수 있다. Cache를 사용하면서 빠른 사용자 경험을 제공할 수 있었다.
캐시 적용 사례
HTTP/1.1 200 OK
Content-Type: image/jpeg
cache-control: max-age=60
Content-Length: 34012
.....
위와 같이 `cache-control` 옵션을 사용하여 60초 임을 명시해두면 클라이언트의 웹 브라우저 캐시에 저장되어 다시 사용자가 해당 자료를 요청했을 때 네트워크를 통해 다시 불러오지 않고 빠르게 응답할 수 있다.
캐시 시간이 초과 되었을 때(60초 후)
60초 후에는 캐시 시간이 만료되었고 결국 다시 네트워크를 통해 똑같은 데이터를 다시 받아야하는 효율의 문제가 생기게 된다. 이런 경우를 대비해 HTTP 스펙을 작성한 엔지니어들은 `검증 헤더`라는 것을 만들었다.
검증 헤더와 조건부 요청
위의 문제점을 해결하기 위해서 서버는 `Last-Modified` 헤더 옵션을 사용하여 마지막으로 수정된 시간을 헤더에 담아 보낸다.
HTTP/1.1 200 OK
Content-Type: image/jpeg
cache-control: max-age=60
Last-Modified: 2020년 11월 10일 10:00:00
...
클라이언트는 서버에서 마지막으로 데이터가 수정된 시간의 정보까지 함께 캐싱하여 두고 60초가 흐른 후 캐시가 만료되어 클라이언트에서 서버에 다시 요청할 때 `if-modified-since` 헤더 옵션을 사용하여 요청한다.
GET /star.jpg
if-modified-since: 2020년 11월 10일 10:00:00
서버는 이 옵션값을 통해 요청하는 데이터가 수정이 되었는지 판단하게 되고 수정되지 않았다면 304 Not Modified HTTP 상태코드와 함께 HTTP BODY가 없는 채로 응답하게 된다.
HTTP/1.1 304 Not Modified
Content-Type: image/jpeg
cache-control: max-age=60
Last-Modified: 2020년 11월 10일 10:00:00
Content-Length: 34012
이로써 응답시에는 HTTP BODY가 없기 때문에 상당한 양의 네트워크 사용을 줄일 수 있게 된다.
검증 헤더와 조건부 요청 - 단점
이 방식으로 요청을 확인할 때는 다음과 같은 단점을 가지게 된다.
- 1초 미만(0.x초) 단위로 캐시 조정이 불가능
- 날짜 기반의 로직 사용
- 데이터를 수정해서 날짜가 다르지만, 같은 데이터를 수정해서 데이터 결과가 똑같은 경우
- 예) A -> B / B -> A, A의 내용이 B를 경유해서 다시 A라는 같은 데이터지만 날짜 기반의 검증 헤더 값은 이미 변경되었으므로 다시 다운로드 받아야만 함.
- 서버에서 별도의 캐시 로직을 관리하고 싶은 경우
- 예) 스페이스나 주석처럼 크게 영향이 없는 변경에서 캐시를 유지하고 싶은 경우
마지막의 경우처럼 서버 쪽에서 캐시 룰을 고유하게 만들고 싶을 경우 ETag를 사용하여 처리할 수 있다.
ETag, If-None-Match
The ETag or entity tag is part of HTTP, the protocol for the World Wide Web. It is one of several mechanisms that HTTP provides for Web cache validation, which allows a client to make conditional requests. This mechanism allows caches to be more efficient and saves bandwidth, as a Web server does not need to send a full response if the content has not changed. ETags can also be used for optimistic concurrency control[1] to help prevent simultaneous updates of a resource from overwriting each other.
An ETag is an opaque identifier assigned by a Web server to a specific version of a resource found at a URL.[2] If the resource representation at that URL ever changes, a new and different ETag is assigned. Used in this manner, ETags are similar to fingerprints and can quickly be compared to determine whether two representations of a resource are the same.
캐시용 데이터에 임의의 고유한 버전 이름을 달아두는 용도이다.(원본에 대한 해시값을 이용하기도 한다.) 단순하게 ETag만 보내어 현재 클라이언트가 가지고 있는 캐시의 버전이 서버의 버전과 같다면 캐시 데이터를 연장하여 유지하고 다르면 다시 받는 방식으로 진행된다.
ETag 예시
HTTP/1.1 200 OK
Content-Type: image/jpeg
cache-control: max-age=60
ETag: "aaaaaaaa"
Content-Length: 34012
...
클라이언트는 받은 ETag와 함께 데이터를 캐시에 저장한다. 이후 캐시 시간이 초과되어 다시 요청할때는 다음과 같이 `If-None-Match`옵션을 사용하여 저장되어있던 ETag를 함께 보낸다.
GET /star.jpg
If-None-Match: "aaaaaaaa"
서버에서 ETag가 변경되지 않았다면 Last-Modified 방식과 동일하게 HTTP Body는 없이 헤더만 304 상태코드와 함께 응답한다.
HTTP/1.1 304 Not Modified
Content-Type: image/jpeg
cache-control: max-age=60
ETag: "aaaaaaaa"
Content-Length: 34012
캐시와 조건부 요청 헤더 종류들
캐시 제어 헤더
- Cache-Control - 캐시 지시어(directives)
- Cache-Control: max-age - 캐시 유효 시간, 초 단위
- Cache-Control: no-cache - 데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증하고 사용
- Cache-Control: no-store - 데이터에 민감한 정보가 있으므로 저장하면 안됨(메모리에서 사용하고 최대한 빨리 삭제)
- Pragma - 캐시 제어(하위 호환)
- Pragma: no-cache
- HTTP 1.0 하위 호환이므로 지금은 쓰이지 않음
- Expires - 캐시 만료일 지정(하위 호환)
- expires: Mon, 01 Jan 1990 00:00:00 GMT
- 캐시 만료일을 날짜로 지정하는 방식으로 HTTP 1.0부터 사용함.
- 좀 더 유연하게 사용할 수 있는 Cache-Control: max-age을 권장함.
- 하위 호환이므로 두 방식을 함께 사용하면 Expires는 무시됨.
검증 헤더와 조건부 요청 헤더
- 검증 헤더 (Validator)
- ETag: "v1.0", ETag: "asid93jkrgh2l"
- Last-Modified: Thu, 04 Jun 2020 07:19:24 GMT
- 조건부 요청 헤더
- If-Match, If-None-Match: ETag 값 사용
- If-Modified-Since, If-Unmodified-Since: Last-Modified 값 사용
프록시 캐시
미국의 구글 원(Origin) 서버를 한국에서 사용한다면 지금 현재 사용하는 인터넷의 속도보다 느린 사용자 경험을 줄 수 밖에 없을 것이다. 이런 문제를 해결하기 위한 방식으로 프록시 캐시 서버가 한국 어딘가에 존재하여 미국 원(Origin) 서버로 요청하는 다양한 요청들을 받아 처리해준다. 이런 방식은 CDN(Content Delivery Network) 서비스이며 원 서버에 집중적으로 생기는 트래픽 부하를 프록시 캐시 서버를 통해 해결하여 원활한 요청을 받도록 한다. AWS에는 Cloud Front가 존재한다.
프록시 서버의 데이터는 보통 최초 데이터 접근자에 의하여 캐시 서버에 저장되지만, 특수한 경우 직접 데이터를 프록시 캐시 서버에 밀어 넣어 준비할 수도 있다.
이 때 Client 측에 저장되는 캐시를 private cache, 프록시 캐시 서버에 저장되는 캐시를 public cache라고 부르며 캐시 지시어를 통해 Client에 저장될지 프록시 서버에 저장될지 설정할 수 있다.
추가적으로 캐시를 제어할 수 있는 지시어들은 다음과 같다.
- Cache-Control - 기타 캐시 지시어(directives)
- Cache-Control: public - 응답이 public 캐시에 저장되어도 됨
- Cache-Control: private - 응답이 해당 사용자만을 위한 것이므로 private 캐시에 저장되어야 됨(default)
- Cache-Control: s-maxage - 프록시 캐시에만 적용되는 max-age
- Age: 60 (HTTP 헤더) - 오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간(초)
캐시 무효화
설령 원 서버에서 캐시 금지 처리를 하여 보낸다하더라도 몇몇 웹 브라우저에서는 heuristics 처리를 위해 임의로 캐시 처리를 하는 경우가 있다. 이런 경우를 위해서 확실하게 캐시 무효화 응답을 할 수 있도록 HTTP 스펙에서 제공하는데 다음과 같이 모든 제어 옵션을 넣어주어야 한다.
- Cache-Control - 확실한 캐시 무효화 응답 방법
- Cache-Control: no-cache, no-store, must-revalidate
- must-revalidate - 캐시 만료 후 최초 조회시 원 서버에 검증하도록 하는 옵션으로 원 서버 접근 실패시 반드시 오류가 발생해야 함.(504 Gateway Timeout)
- must-revalidate는 캐시 유효 시간이라면 캐시를 사용한다.
- Pragma: no-cache
- 과거 브라우저(HTTP 1.0)를 위한 옵션 처리
- Cache-Control: no-cache, no-store, must-revalidate
no-cache와 must-revalidate를 함께 사용하는 이유
단순히 no-cache만 사용할 경우에 발생하는 문제를 알아보자. Client에서 프록시 서버로 요청을 보냈을 때 원 서버와의 통신 후 데이터를 받아와 제공해주게 된다. 이 때 만약 원 서버의 문제 혹은 네트워크 상의 문제로 인하여 프록시 서버와 원 서버의 연결이 단절된 경우 프록시 서버의 설정 중 원 서버와 연결이 되지 않을 경우를 대비해 과거 데이터를 보내주는 설정이 존재한다고 한다.(이런 설정이 존재하는 이유는 데이터를 아예 못보여주는 것보다 과거 데이터라도 보여주는 것이 좋은 경우가 있기 때문이라고 한다.) 이렇게 되면 실제 원 서버의 데이터와 Client가 받은 데이터가 불일치하게 되는데 만약 이 데이터가 돈과 같이 민감한 데이터라면 큰 손실로 이어질 수 있다.
그렇기 때문에 must-revalidate 옵션을 함께 사용하게 된다. must-revalidate를 사용하게 되면 프록시 서버가 원 서버에 접근이 불가한 경우 HTTP 스펙 상 무조건 504 Gateway Timeout을 응답하도록 상세되어 있으므로 no-cache와 must-revalidate를 함께 사용 하는 것이다.
'노트 정리 > 모든 개발자를 위한 HTTP 웹' 카테고리의 다른 글
[HTTP 웹] 8. HTTP 헤더 - 옵션 종류 (0) | 2022.10.31 |
---|---|
[HTTP 웹] 7. HTTP 헤더 (0) | 2022.10.30 |
[HTTP 웹] 6. HTTP 상태 코드 (0) | 2022.10.29 |
[HTTP 웹] 5. HTTP 메서드 활용 (0) | 2022.10.28 |
[HTTP 웹] 4. HTTP 메서드 (0) | 2022.10.27 |