캐시
캐시 적용 전
첫 번째 요청
첫 번째 요청에서 1.1M를 전송받았다.
두 번째 요청
같은 사진을 두 번째로 요청했음에도 똑같이 1.1M를 전송받았다.
정리
- 캐시가 없는 경우 데이터가 변경되지 않아도 네트워크를 통해서 계속 데이터를 받아야 한다.
- 네트워크는 매우 느리고 비싸며 브라우저 로딩 속도는 느리다. 이는 느린 사용자 경험으로 이어진다.
캐시 적용 후
첫 번째 요청
서버에서 캐시 유효 시간을 지정하여 데이터를 전달하면 브라우저는 응답 데이터를 캐시에 저장하게 된다.
두 번째 요청
두 번째 요청이 발생하는 경우 서버로 요청하지 않고 캐시 저장소에 있는 캐시 유효 시간을 검증한다.
캐시가 사용 가능한 상태인 경우 캐시에서 해당 이미지를 찾아 사용하게 된다.
만약 캐시 시간이 초과되면 어떻게 될까?
캐시 유효 시간이 초과되면, 서버를 통해 데이터를 다시 조회하고, 캐시를 갱신한다.
정리
- 캐시 덕분에 캐시 유효 시간 동안 네트워크를 사용하지 않아도 된다.
- 따라서 비싼 네트워크 사용량을 줄일 수 있으며, 브라우저 로딩 속도 또한 빨라진다.
- 빠른 사용자 경험을 제공할 수 있다.
캐시 시간 초과
- 캐시 유효 시간이 초과해서 서버에 다시 요청하면 두 가지 상황이 나타난다.
- 서버에서 기존 데이터를 변경한 상황
- 서버에서 기존 데이터를 변경하지 않은 상황
만약 캐시 만료 후에도 기존 데이터가 변경되지 않았으면 굳이 다시 다운로드할 필요가 없다.
재요청하는 대신 캐시해 두었던 데이터를 재사용할 수 있다.
단 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있는 방법이 필요하다.
검증 헤더를 이용하여 재요청 최소화
첫 번째 요청
서버에서 캐시 유효 시간뿐만 아니라 데이터 최종 수정 시간을 함께 보낸다.
두 번째 요청 - 캐시 시간 초과
캐시가 만료된 경우 데이터 최종 수정 시간과 함께 재요청을 한다.
각각의 데이터 최종 수정일을 확인한다.
데이터 수정일이 일치하는 경우 304 Not Modified메시지와, 캐시 유효 시간, 최종 수정일을 다시 전송한다.
이후 다시 캐시에서 데이터를 꺼내 사용한다.
정리
- 캐시 유효 시간이 초과되어도 서버의 데이터가 갱신되지 않았으면 304 Not Modified + 헤더의 메타 데이터만 응답한다(바디 x)
- 클라이언트는 서버가 보낸 헤더 데이터로 캐시의 메타 데이터를 갱신한다.
- 클라이언트는 캐시 되어 있는 데이터를 재활용한다.
- 결과적으로 네트워크 다운로드가 발생하긴 하지만 데이터를 재전송받는 방식이 아닌 헤더 데이터만 다운로드하는 방식이기에 기존 네트워크 발생량보다 현저히 적다.
검증 헤더와 조건부 요청
검증 헤더
- 캐시 데이터와 서버 데이터가 같은지 검증하는 데이터
- Last-Modified, ETag
조건부 요청 헤더
- 검증 헤더로 조건에 따른 분기
- If-Modified-Since: Last-Modified 사용
- If-None-Match: ETag 사용
- 조건이 만족하는 경우 200OK
- 조건이 만족하지 않으면 304 Not Modified
예시
If-Modified-Since: 이후에 데이터가 수정되었으면?
- 데이터 미변경 예시
- 캐시: 2020년 11월 10일 10:00:00 vs 서버: 2020년 11월 10일 10:00:00
- 304 Not Modified, 헤더 데이터만 전송(Body 미포함)
- 전송 용량 0.1M
- 데이터 변경 예시
- 캐시: 2020년 11월 10일 10:00:00 vs 서버: 2020년 11월 10일 11:00:00
- 200 OK, 모든 데이터 전송(Body 포함)
- 전송 용량 1.1M
Last-Modified, If-Modified-Since 단점
- 1초 미만 단위로 캐시 조정이 불가능하다.
- 날짜 기반의 로직을 사용한다.
- 데이터를 수정해서 날짜가 다르지만, 데이터의 결과가 똑같은 경우(파일의 날짜만 갱신되는 경우) 재요청을 하게 된다.
- 서버에서 별도의 캐시 로직을 관리하고 싶은 경우 어려움이 있다.
- space, 주석처럼 크게 영향이 없는 변경에서 캐시를 유지하고 싶은 경우
ETag, If-None-Match
- ETag(Entity Tag)
- 캐시용 데이터에 임의의 고유한 버전을 달아두는 것이다.
- 날짜가 아닌 버전 혹은 해시 값이라고 생각하면 쉽다.
- 예) ETag: "v1.0", ETag: "a2jiodwjekjl3"
- 데이터가 변경되면 ETag 값을 변경한다
- 예) ETag: "aaaa" -> ETag: "bbbb"
- 단순히 ETag 값만 보내서 같으면 유지, 다르면 다시 받는 것이다.
간단히 말해서 데이터가 같으면 ETag 값이 일치하고 다르면 ETag 값이 일치하지 않는다.
따라서 날짜만 수정된 경우에 재요청을 하지 않는다.
ETag 사용 예시
첫 번째 요청
두 번째 요청 - 캐시 시간 초과
캐시와 서버의 ETag 값을 비교한다.
정리
- 단순하게 ETag 값만 서버에 보내서 같으면 유지하고 다르면 다시 받으면 된다.
- 캐시 제어 로직을 서버에서 완전히 관리할 수 있다.
- 클라이언트는 단순히 ETag 값을 서버에 제공한다.(클라이언트는 캐시 메커니즘을 모른다)
- 예)
- 서버는 베타 오픈 기간 3일 동안 파일이 변경되어도 ETag 값을 동일하게 유지한다.
- 베타 기간 3일 동안은 같은 ETag 값을 계속 사용한다.
파일 내용이 바뀌어도 서버는 일부러 ETag 값을 유지하여, 브라우저가 기존 캐시를 계속 사용하도록 유도할 수 있다.
- 베타 기간 3일 동안은 같은 ETag 값을 계속 사용한다.
- 애플리케이션 배포 주기에 맞추어 ETag값을 모두 갱신시킨다.
- 정식 배포 타이밍에는 ETag값을 전부 새로 생성한다.
이렇게 하면 브라우저는 ETag 값이 달라졌다는 걸 감지하고, 모든 캐시를 갱신시킬 수 있다.
- 정식 배포 타이밍에는 ETag값을 전부 새로 생성한다.
- 서버는 베타 오픈 기간 3일 동안 파일이 변경되어도 ETag 값을 동일하게 유지한다.
캐시 제어 헤더
- Cache-Control: 캐시 제어
- Pragma: 캐시 제어(하위 호환)
- Expires: 캐시 유효 기간(하위 호환)
Cache-Control
캐시 지시어
- Cache-Control: max-age
- 캐시 유효 시간, 초 단위
- Cache-Control: no-cache
- 데이터는 캐시해도 되지만, 항상 원 서버에 검증하고 사용
- Cache-Control: no-store
- 데이터에 민감한 정보가 있으므로 저장하면 안 됨
- 메모리에서 사용 후 최대한 빨리 삭제
- Cache-Control: must-revalidate
- 캐시 만료 후 최초 조회 시 원 서버에 검증해야 함
- 원 서버 접근 실패 시 반드시 오류가 발생해야 함 - 504(Gateway Timeout)
- must-revalidate는 캐시 유효 시간이 지나지 않았다면 캐시를 사용
no-cache와 must-revalidate 둘 다 캐시 만료 후 원 서버에 검증하는 게 똑같지 않냐라고 생각할 수 있다.
맨 마지막을 참고하자.
캐시 지시어 - 기타
- Cache-Control: public
- 응답이 public 캐시에 저장되어도 된다. (youtube)
- Cache-Control: private
- 응답이 해당 사용자만을 위한 것이다. private 캐시에 저장해야 한다. (사용자 정보)
- Cache-Control: s-maxage
- 프록시 캐시에만 적용되는 max-age
Pragma
잘 사용하지 않는다
Expires
캐시 만료일 지정(하위 호환)
- expires: Mon, 01 Jan 1990 00:00:00 GMT
- 캐시 만료일을 정확한 날짜로 지정한다.
- HTTP 1.0부터 사용해 왔다.
- 지금은 더 유연한 Cache-Control: max-age 사용을 권장한다.
- 만약 Cache-Control와 함께 사용하면 Expires는 무시된다.
검증 헤더와 조건부 요청 헤더
검증 헤더
- ETag: "v1.0", ETag: "asid93das"
- 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초가 걸린다. 더 빠르게 접근할 수는 없을까?
프록시 캐시 도입
첫 번째 요청
첫 번째 요청의 경우 프록시 서버에도 해당 데이터가 캐시가 되지 않아 느릴 수 있다.
두 번째 요청
두 번째 요청의 경우 프록시 서버에 해당 데이터가 public 캐시로 저장되어 빠른 접근이 가능하다.
우리가 유튜브에서 한국 사람들이 보지 않은 영상을 본 경우 느렸던 경험이 있을 것이다.
이는 아직까지 프록시 서버에 해당 영상 데이터가 캐시 되지 않아 그런 것이다.
이처럼 서버 간의 거리가 먼 경우 프록시 서버를 도입하여 응답 시간을 최소화할 수 있다.
대표적으로 AWS CDN 서비스인 CloudFront가 있다.
캐시 무효화
캐시를 요청하지 않아도 GET 요청 시 브라우저에서 캐시 시키는 경우가 있다.
사용자의 통장 잔고 같이 민감한 정보들은 캐시 되지 않아야 한다.
확실한 캐시 무효화 응답 방법
- Cache-Control: no-cache, no-store, must-revalidate
no-cache vs must-revalidate
기본 동작 과정
no-cache와 must-revalidate 둘 다 검증 과정은 같다.
하지만 만약 순간적인 오류로 원 서버에 접근이 불가하다면 어떤 차이가 날까?
no-cache
no-cache의 경우 일시적인 오류가 발생하면 오류를 나타내지 않고 오래된 데이터를 제공한다.
must-revalidate
must-revalidate의 경우 오류가 발생하면 오래된 데이터를 제공하는 것이 아닌 오류를 나타낸다.
계좌 정보로 예시를 들어보자.
일시적인 오류가 발생했다는 메시지와 이전 계좌 잔액 중 무엇을 나타내는 게 사용자에게 좋을까?
당연히 일시적 오류 메시지를 제공하는 게 좋다.
이처럼 항상 최신 상태를 유지해야 하는 데이터의 경우 must-revalidate를 사용해야 한다.
출처 : https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC/dashboard
'CS' 카테고리의 다른 글
CSRF (0) | 2025.04.08 |
---|---|
HTTP 헤더, 쿠키에 대해서 (0) | 2025.04.07 |
HTTP 상태 코드 (0) | 2025.04.04 |
HTTP 메서드 활용 (0) | 2025.04.03 |
[ 프로그래머스,bfs ] 네트워크.python (0) | 2025.04.03 |