Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
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
Archives
Today
Total
관리 메뉴

가능세계

[Network] 캐시와 조건부 요청(Cache & Conditional request) 정리하기 본문

Blog/Network

[Network] 캐시와 조건부 요청(Cache & Conditional request) 정리하기

cona-tus 2023. 9. 11. 18:47

network-icon

 

네트워크를 통해 리소스를 가져오는 과정은 느리며 비용이 많이 듭니다. 동일한 이미지를 반복해서 요청하면 데이터를 다시 다운로드해야 하므로 웹 사이트의 로딩 속도와 사용자 경험이 저하될 수 있습니다.

 

이처럼 불필요한 네트워크 요청을 어떻게 피할 수 있을까요?

 

여기서 HTTP 캐시라는 개념이 등장합니다.



1. 캐시란 무엇인가요?

1-1. 캐시(Cache)와 캐싱(Caching)

캐시(Cache)는 자주 사용되는 데이터를 임시로 복사해 두는 저장소를 의미합니다.

 

그리고 데이터를 캐시에 저장하는 행위를 캐싱(Caching)이라고 합니다.

캐싱주어진 리소스를 저장하고 재사용하여 보다 빠르게 액세스 할 수 있도록 하는 프로세스라고 할 수 있습니다.

 

1-2. HTTP 캐시

네트워크를 사용하는 웹 환경에도 캐시 개념을 적용할 수 있습니다.

 

웹 캐시가 자신의 저장소 내에 요청된 리소스를 가지고 있다면, 원래의 서버로부터 리소스를 다시 다운로드하는 대신 리소스의 복사본을 반환합니다.

 

이로써 비싼 네트워크 사용량을 줄일 수 있으며, 브라우저 로딩 속도가 향상되어 사용자 경험을 최적화할 수 있습니다.



2. HTTP 캐싱은 어떻게 작동하나요?

가장 기본적으로 캐싱 프로세스는 다음과 같이 작동합니다.

 

cache01

 

cache02

  1. 웹 사이트는 원본 서버에 리소스를 요청합니다.
  2. 시스템은 캐시를 확인하여 해당 리소스의 복사본이 있는지 여부를 판단합니다.
  3. 리소스가 캐시에 저장되어 있다면, 리소스는 캐시에서 제공됩니다.
  4. 리소스가 캐시에 없는 경우, 파일은 원본 소스에서 제공됩니다.
  5. 캐시 유효 시간이 만료되거나 캐시가 지워질 때까지 리소스는 계속해서 캐시에서 제공됩니다.



3. 검증 헤더와 조건부 요청

만약 캐시 만료 후에도 서버에서 데이터를 변경하지 않았다면, 데이터를 전송하는 대신에 저장해둔 캐시를 재사용할 수 있습니다.

 

단, 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인하는 방법이 필요합니다. 이런 과정을 캐시 유효성 검증(Validation) 및 조건부 요청(Conditional request)이라고 합니다.

 

캐시의 리소스가 오래되면 클라이언트는 리소스가 여전히 유효한지 확인하기 위해 조건부 요청을 보낼 수 있습니다.

 

검증 헤더로 캐시 데이터와 서버 데이터가 일치하는지 여부를 확인하며, 검증 헤더는 최종 수정 시간을 나타내는 Last-Modified와, 특정 리소스 버전을 나타내는 ETag로 나뉘어집니다.

 

3-1. If-Modified-Since는 Last-Modified를 사용합니다

1. 최초 요청

GET /index.html HTTP/1.1
Host: example.com

 

2. 최초 요청 시 응답

HTTP/1.1 200 OK
Content-Type: text/html
Last-Modified: Sat, 03 Sep 2022 00:00:00 GMT
Content-Length: 157

<message body contains resource>

웹 브라우저는 Last-Modified 헤더와 함께 응답 결과를 캐시에 저장합니다.

Last-Modified 헤더는 데이터가 마지막으로 수정된 시간을 나타냅니다.

 

3. 두 번째 요청

GET /index.html HTTP/1.1
Host: example.com
If-Modified-Since: Sat, 03 Sep 2022 00:00:00 GMT

캐시에 저장해 둔 Last-Modified 값, 즉 캐시의 최종 수정일을 If-Modified-Since라는 HTTP 요청 헤더에 넣어 서버에 요청을 보냅니다.

 

4. 리소스가 변경되지 않았을 경우 두 번째 응답

HTTP/1.1 304 Not Modified
Last-Modified: Sat, 03 Sep 2022 00:00:00 GMT

클라이언트에서 보내는 If-Modified-Since와 서버의 Last-Modified를 비교하여 데이터가 갱신된 부분이 없는지 판단합니다.

 

만약 조건부 요청을 보냈는데 원본 리소스에 아무런 변경이 없었다면, 서버는 304 Not Modified라는 상태 코드로 응답합니다.

 

데이터에 수정된 것이 없으므로 이 응답에는 바디를 제외한 헤더 메타 정보만 전송됩니다.

 

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

이로써 네트워크 부하가 줄어들고, 트래픽을 아낄 수 있습니다.

 

5. 세 번째 요청

GET /index.html HTTP/1.1
Host: example.com
If-Modified-Since: Sat, 03 Sep 2022 00:00:00 GMT

 

6. 리소스가 변경되었을 경우 세 번째 응답

HTTP/1.1 200 OK
Content-Type: text/html
Last-Modified: Sun, 04 Sep 2022 00:00:00 GMT
Content-Length: 250

<message body contains resource>

 

3-2. Last-Modified와 If-Modified-Since의 한계점

Last-ModifiedIf-Modified-Since의 사용에는 단점이 있습니다. ms 단위로 캐시 조정이 불가능하며, 날짜 기반의 정해진 로직을 사용해야 한다는 것입니다.

 

데이터를 수정하면 파일의 날짜가 갱신된다는 것을 생각해 봅시다.

만약 데이터를 A->B->A로 수정한다면 어떨까요? 이 경우 실제 콘텐츠 자체는 수정되지 않았지만, 날짜가 변경되었으므로 전체 데이터를 다시 다운로드 받아야 합니다.

 

혹은 스페이스나 주석처럼 크게 영향이 없는 경우에는 캐시를 유지하고 싶을 수도 있습니다.

이처럼 Last-ModifiedIf-Modified-Since는 서버에서 별도의 캐시 로직을 관리하고 싶은 경우, 사용이 적합하지 않습니다.

 

이러한 한계점에 대응하여 서버에서 완전하게 캐시 메커니즘을 컨트롤할 수 있는 방법이 있습니다. 바로 Etag입니다.



3-3. If-None-Match는 ETag를 사용합니다

ETag(Entity Tag)는 캐시용 데이터에 대한 임의의 식별자입니다.

 

예로는 ETag: "v1.0", ETag: "a2jiodwjekjl3"가 있습니다.

 

데이터가 갱신되면 Hash를 재생성해 이 이름을 변경합니다. ETag가 같으면 캐시를 유지하고, 다르면 전체 데이터를 다시 받도록 합니다.

 

클라이언트는 캐시 메커니즘을 모른 채 단순히 ETag 값을 서버에 제공하면 되므로, 서버에서 캐시 제어 로직을 완전히 관리하게 됩니다.

 

1. 최초 요청

GET /index.html HTTP/1.1
Host: example.com

 

2. 최초 요청 시 응답

HTTP/1.1 200 OK
Content-Type: text/html
ETag: "abcdefg"
Content-Length: 157

<message body contains resource>

웹 브라우저는 ETag 헤더와 함께 응답 결과를 캐시에 저장합니다.

 

3. 두 번째 요청

GET /index.html HTTP/1.1
Host: example.com
If-None-Match: "abcdefg"

이후 캐시 시간이 초과되어 리소스에 대한 재요청 시 If-None-Match 헤더에 저장해 둔 ETag 값을 넣어서 보냅니다.

 

4. 리소스가 변경되지 않았을 경우 두 번째 응답

HTTP/1.1 304 Not Modified
ETag: "abcdefg"

원본 리소스가 변경되지 않아 ETag 값이 같으면, 서버는 메시지 바디를 제외하고, 304 Not Modified로 응답합니다.

클라이언트는 내부적으로 캐시를 갱신하고, 캐시에 저장되어 있는 데이터를 재활용합니다.

 

5. 세 번째 요청

GET /index.html HTTP/1.1
Host: example.com
If-None-Match: "abcdefg"

 

6. 리소스가 변경되었을 경우 세 번째 응답

HTTP/1.1 200 OK
Content-Type: text/html
ETag: "hijklmn"
Content-Length: 500

<message body contains resource>




참고