| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- 지연 로딩
- 페이징
- 서블릿 컨테이너
- Web
- DLQ
- JWT
- @Transactional
- Dead Letter Queue
- MSA
- Spring
- Routing Key
- JdbcTemplate
- 컨테이너
- Spring Data JPA
- docker
- 쿠버네티스
- kafka
- AWS
- securitycontextholderfilter
- dockerhub
- @ComponentScan
- redis
- mybatis
- 스프링 부트
- Spring Container
- docker compose
- CORS
- DI
- JPA
- JPQL
- Today
- Total
look-forest
HTTP Header - 캐시와 조건부 요청 본문
이번 시간에는 캐시와 캐시 관련 헤더에 대해 알아보겠다.
캐시 기본 동작
캐시가 없으면..
데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운로드 받아야 한다

인터넷 네트워크는 매우 느리고 비싸다 → 브라우저 로딩 속도가 느려진다 → 느린 사용자 경험
캐시를 도입하자!
1. 응답 메시지에 cache-control 필드를 추가

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

3. 이후 요청은 브라우저 캐시에서 꺼내쓴다!

캐시 덕분에 캐시 가능 시간 동안 네트워크를 사용하지 않아도 된다!!
그런데
캐시 유효 시간이 초과하면, 서버를 통해 데이터를 다시 받아 캐시를 갱신한다

리소스는 바뀐 게 없는데, 굳이 이런 바보 같은 짓을 해야 할까?
검증 헤더와 조건부 요청
캐시 유효 시간 초과 시
캐시 유효 시간이 초과해서 서버에 다시 요청하면 다음 두 가지 상황이 나타난다.
1. 서버에서 기존 데이터를 변경함
2. 서버에서 기존 데이터를 변경하지 않음 → 데이터를 전송하는 대신에 저장해 두었던 캐시를 재사용할 수 있다
그럴려면 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있는 방법이 필요하다.
[방법 1] Last-Modified와 If-Modified-Since
1. 응답 메시지에 검증 헤더 추가

2. 캐시 시간 초과로 재요청 시, 조건부 요청

3. 검증

4. 응답
- 데이터 변경 시, 200 OK, 모든 데이터 전송(BODY 포함)
- 서버의 데이터가 갱신되지 않았다면 304 Not Modified 응답 (헤더 메타 정보만 응답, 바디 X)

클라이언트는 서버가 보낸 응답 헤더 정보로 캐시의 메타 정보를 갱신하고, 캐시에 저장되어 있는 데이터를 재활용한다.

Last-Modified, If-Modified-Since 단점
- A에서 B로 바꾸고 다시 A로 바꿨다면? (A→B→A)
실제 데이터는 결과적으로 바뀐 게 없으나 수정 날짜는 변경됐다. - 서버에서 별도의 캐시 로직을 관리하고 싶은 경우에 적합하지 않다.
예) 스페이스나 주석처럼 크게 영향이 없는 변경에서 캐시를 유지하고 싶은 경우
[방법 2] ETag, If-None-Match
ETag 같으면 유지, 다르면 다시 받기!
ETag(Entity Tag)란?
- 캐시용 데이터에 임의의 고유한 버전 이름을 달아둔다. (*Hash를 사용하기도 한다)
예) ETag: "v1.0", ETag: "a2jiodwjekjl3" - 데이터가 변경되면 이 이름을 변경하거나 Hash를 다시 생성
※ Hash는 파일 내용이 동일하면 같은 해시값을 갖는다는 것을 활용
1. 응답 메시지에 검증 헤더 추가

2. 캐시 시간 초과로 재요청 시, 조건부 요청

3. 검증
- ETag 비교하여 데이터 변경 여부 확인
4. 응답
- 데이터 변경 시, 200 OK, 모든 데이터 전송(BODY 포함)
- 서버의 데이터가 갱신되지 않았다면 304 Not Modified 응답 (헤더 메타 정보만 응답, 바디 X)
ETag, If-None-Match의 장점
캐시 제어 로직을 서버에서 완전히 관리할 수 있다
예)
서버는 베타 오픈 기간인 3일 동안 파일이 변경되어도 ETag를 동일하게 유지
애플리케이션 배포 주기에 맞추어 ETag 모두 갱신
캐시와 조건부 요청 헤더
캐시 제어 헤더
- Cache-Control: 캐시 지시어(directives)
- Cache-Control: max-age
캐시 유효 시간(초 단위) - Cache-Control: no-cache
데이터는 캐시에 저장해도 되지만, 항상 원(origin) 서버에 검증하고 사용 - Cache-Control: no-store
데이터에 민감한 정보가 있으므로 저장하면 안됨 (메모리에서 사용하고 최대한 빨리 삭제)
- Cache-Control: max-age
- Pragma: 캐시 제어 (HTTP 1.0 하위 호환)
Pragma: no-cache (데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증하고 사용) - Expires: 캐시 유효 기간 (HTTP 1.0 하위 호환)
expires: Mon, 01 Jan 1990 00:00:00 GMT (초 단위가 더 유연하므로 Cache-Control: max-age 권장)
검증 헤더 (Validator)
- Etag
- Last-Modified
조건부 요청 헤더
- If-Match, If-None-Match: ETag 값 사용
- If-Modified-Since, If-Unmodified-Since: Last-Modified 값 사용
프록시 캐시
[문제] 원 서버 직접 접근
인터넷 네트워크는 매우 느리고 비싸므로, 멀리 있는 서버일수록 느리다.

[해결] 프록시 캐시 도입
가까운 프록시 캐시 서버에 원 서버의 데이터를 저장해둔다!
DNS을 조정하여, 클라이언트가 프록시 서버를 거쳐 오도록 한다.

※ CDN도 같은 원리이다.
CDN (Contents Distribution Network)
비디오 데이터를 단일 거대 데이터 센터에서 제공할 경우,
- 먼 지점에 있는 경우 느리다 (많은 네트워크를 거칠수록 throughput 낮아질 수 있음)
- 인기 있는 비디오가 동일 링크로 여러 번 반복 전송되는 낭비
- 장애가 발생하면 전체 서비스가 중단될 수 있다
따라서 비디오 스트리밍 회사(컨텐츠 제공자)들은 CDN을 이용한다.
CDN은 다수의 지점에 분산된 서버를 운영하여, 복사본을 이들 분산 서버에 저장한다.
URL을 지정하여 특정 비디오를 요청하면,
CDN은 DNS를 이용해 요청을 가로채고 클라이언트에게 가장 적당한 클러스터를 연결한다.
사용자는 최선의 사용자 경험을 제공할 수 있는 지점의 CDN 서버로 연결된다.
그래서 유튜브에서 인기 많은 영상은 빠르게 볼 수 있고, 사람들이 많이 보지 않는 영상은 느린 것이다!
프록시 캐시 서버 관련 헤더
- Cache-Control: private (기본값)
응답이 해당 사용자만을 위한 것이다. 따라서 private 캐시에만 저장해야 한다. (로그인 내역 등) - Cache-Control: public
응답이 public 캐시에 저장되어도 된다. - Cache-Control: s-maxage
프록시 캐시에만 적용되는 max-age.
캐시 무효화
[문제 상황]
서버가 요청하지 않아도, 웹 브라우저가 임의로 캐시해버릴 수 있다.
통장 잔고 등 계속 갱신되는 정보를 캐시해서 쓰면 안되기 때문에, 캐시하지 말라고 응답해야 한다.
확실한 캐시 무효화 응답을 위해 넣어야 하는 헤더 필드 값
확실한 캐시 무효화를 위해서는 아래 4가지를 전부 넣어줘야 한다.
- Cache-Control: no-store, no-cache, must-revalidate
- Pragma: no-cache (HTTP 1.0 하위 호환을 위해. HTTP 1.0은 Cache-control을 모른다)
no-store, no-cache, must-revalidate가 의미하는 것
- Cache-Control: no-store
데이터에 민감한 정보가 있으므로 저장하면 안된다. 메모리에서 사용하고 최대한 빨리 삭제해라. - Cache-Control: no-cache
데이터는 캐시에 저장해도 되지만, 항상 원 서버에 검증하고 사용해라 - Cache-Control: must-revalidate
캐시 만료후 최초 조회시 원 서버에 검증해야 한다. (캐시 유효 시간이라면 캐시를 사용한다)
※ no-store만으로 캐시가 무효화되어야 하나, 모호한 부분들이 존재해서 이것저것 다 때려 박는 것이다.
그런데, no-cache, must-revalidate은 기능이 겹치는 것 같은데 왜 둘 다 써야 하는가?
no-cache와 must-revalidate의 차이
[no-cache 기본 동작]
프록시 서버는 no-cache를 보고 원 서버에 요청을 전달한다

[no-cache가 에러에 대응하는 자세]
프록시 캐시 서버는 no-cache일 때, 원 서버와 통신이 되지 않아도 에러를 내지 않는다

[must-revalidate가 에러에 대응하는 자세]
must-revalidate는 원 서버 접근 실패 시 오류를 발생시킨다. (504, Gateway Timeout)

참고 자료 & 이미지 출처
모든 개발자를 위한 HTTP 웹 기본 지식 (김영한 님)
컴퓨터 네트워킹 : 하향식 접근 7판 (JAMES F.KUROSE)
'Web > HTTP' 카테고리의 다른 글
| HTTP Header - 일반 헤더 (0) | 2021.05.31 |
|---|---|
| HTTP 상태 코드 (0) | 2021.05.28 |
| HTTP 메서드 활용 (0) | 2021.05.24 |
| HTTP 메서드 (0) | 2021.05.24 |
| HTTP 기본 (0) | 2021.05.17 |