Web cache 이해하기

최근에 개발한 기능이 매우 느리다는 이슈가 있었다. 캐시가 되면 더 빠르게 동작할 것이라고 가정했는데 이 웹 캐시를 다뤄본 적이 없어서 막막했다. 이번 기회에 웹 캐시에 대해 좀 더 deep-dive 해봤다.😀

🪼 웹 서비스 캐시 이해하기

1. 웹 서비스에서 캐시란 무엇일까?

이를 통해 사용자가 웹사이트를 방문하거나 서비스를 이용할 때, 매번 서버에서 데이터를 새로 불러오는 대신 이미 저장해 둔 데이터를 사용함으로써 로딩 시간을 줄이고, 서버의 부하를 감소시키게 한다.
예를 들어, 자주 방문하는 웹사이트의 이미지나 로고 같은 정적인 요소는 캐시를 통해 저장되므로, 다음 방문 때 빠르게 화면에 표시될 수 있다. 이는 인터넷 사용 경험을 향상시키고, 효율적인 데이터 처리를 가능하게 한다.

2. 캐시의 생명주기

웹 브라우저가 서버에서 요청한 적이 없는 리소스를 가져오려고 할 때, 서버와 브라우저는 HTTP 요청-응답을 주고 받는다.
이후, HTTP 응답에 포함된 cache-control 헤더에 따라 받은 리소스의 생명주기(만료기간,캐시 정책)가 결정된다.

3. 캐시의 유효기간

캐시의 유효기간은 서버의 cache-control 헤더 값으로 Max-age에 들어간 값을 보면 알 수 있다.
Max-age:second라고 하면 유효한 기간은 second초가 된다.

한번 브라우저에 캐시가 저장되면 만료될 때까지, 캐시는 계속 브라우저에 남는다.
그렇기에 CDN Invalidation을 포함한 서버의 작업이 있어도 브라우저의 유효한 캐시를 지우기 어렵다.

4. 캐시 유효기간 지난 후 재검증

캐시 유효기간 지나면 캐시가 완전히 사라지는 것은 아니다.
대신 브라우저는 서버에 조건부 요청을 해서 캐시가 유효한지 재검증을 한다. 재검증 결과로 브라우저가 가지고 있는 캐시가 유효하다면, 서버는 304 not modified 요청을 내려준다.
재검증 결과 캐시가 유효하지 않으면, 서버는 200OK 또는 적합한 상태 코드를 내려준다. max-age=0이 cache-control 헤더로 설정되었을 때, 매번 리소스를 요청할 때마다 서버에 재검증 요청을 보내야 한다.

5. 중간 서버와 CDN의 역할

CDN과 같은 중간 서버를 사용하면 캐시는 여러 곳에 생긴다. 서버가 가지는 원래 응답을 CDN이 캐시하고 CDN의 캐시된 응답은 사용자 브라우저가 다시 가져와서 캐시한다.

사용자 브라우저 => CDN => 서버

즉, HTTP 캐시는 여러 레이어에 저장될 수 있기에 전체 캐시 날리려면 각각의 캐시(브라우저 캐시, CDN캐시)를 날려야 한다.
한번 저장된 캐시는 지우기 어려워서 cache-control의 max-age값은 신중하게 설정해야 한다.

6. cache-control 상세

HTTP 요청, 응답에 대한 캐싱 동작을 제어하는 헤더이다. 캐싱은 이전에 수행한 요청 또는 응답 결과를 재사용하여 네트워크 성능을 향상시키고 대역폭을 줄일 수 있는 메커니즘이다. ex) cache-control: no-cache
서버 및 중간 캐시에 응답 결과를 캐시하지 않도록 한다. 항상 서버로부터 최신의 응답을 받을 수 있다. 그러나 이는 캐싱의 이점을 제한하고 네트워크 성능에 영향을 준다.
cache-control의 기본 값은 public,max-age=0이다. public의 의미는 공개 캐시에 저장할 수 있다는 것이다. 중간 캐시 서버등에 응답이 저장 될 수 있다는 걸 의미

🐡 웹 캐시 전략에 대하여

1. 캐시 유효기간 설정

적절한 Max-age 값 설정을 통해 사용자에게 최신 정보를 제공하면서도 서버 부하를 최소화할 수 있다.

2. S-maxage와 CDN 캐시

S-maxage를 통해 CDN에서의 캐시 유지 기간을 설정할 수 있다. 이를 통해 브라우저와 CDN 사이의 캐시 정책을 다르게 설정하여 효율적인 캐시 관리가 가능하다.
cache-control값을 S-maxage = 31536000, max-age=0과 같이 설정하면 CDN에서는 1년동안 캐시되지만, 브라우저에서는 매번 재검증 요청 보내도록 설정된다.

🐠 ETag와 Last-Modified 헤더의 역할

웹 서비스에서 캐시의 효율적인 관리와 최신성 유지는 매우 중요하다. 이를 위해 ETagLast-Modified 헤더가 사용되는데, 이 두 헤더는 캐시 재검증 과정에서 핵심적인 역할을 한다.

1. ETag 헤더

ETag는 “Entity Tag”의 약자로, 리소스의 고유 식별자를 나타낸다.
이 식별자는 리소스가 변경될 때마다 갱신되므로, 서버와 클라이언트는 ETag 값을 비교함으로써 리소스의 최신 여부를 판단할 수 있다. 예를 들어, 웹 페이지에서 사용하는 이미지 파일이 변경되었다면, 해당 파일의 ETag 값도 새로운 값으로 갱신된다.
클라이언트는 저장된 캐시의 ETag 값과 서버의 ETag 값을 비교하여, 다운로드할 필요가 있는지 결정한다.

2. Last-Modified 헤더

Last-Modified 헤더는 리소스가 마지막으로 변경된 시간을 나타낸다. 클라이언트는 이 시간을 기준으로 리소스가 자신이 가진 버전보다 최신인지를 판단할 수 있다. 예를 들어, 클라이언트가 마지막으로 받은 리소스의 변경 시간이 2024년 4월 20일이라면, 그 이후에 변경된 리소스가 있다면 다시 다운로드를 요청할 수 있다.

3. 구체적 예시 (ex.웹 페이지의 이미지 캐시 재검증)

1단계) 최초 요청 및 응답

  • 서버는 이미지 파일에 대한 응답으로 ETag 값(“image12345etag”)과 Last-Modified(“Wed, 21 Apr 2024 07:28:00 GMT”) 헤더를 전송한다.
  • 브라우저는 이미지를 캐시에 저장하고, ETag 값과 Last-Modified 값을 캐시 메타데이터로 함께 저장한다.

2단계: 재방문시 캐시 재검증 요청

  • 사용자가 다시 같은 웹 페이지를 방문할 때, 브라우저는 이미지를 다시 다운로드하지 않고, 캐시에 저장된 ETag 값Last-Modified 값을 서버에 전송하여 재검증을 요청한다.
  • 이때, If-None-Match 헤더에 ETag 값(“image12345etag”)과 If-Modified-Since 헤더에 Last-Modified 시간(“Wed, 21 Apr 2024 07:28:00 GMT”)을 포함시켜 서버에 전송하게 된다.

3단계: 서버의 재검증 및 응답

  • 서버는 요청받은 ETag 값과 Last-Modified 시간을 현재 서버 상의 이미지 파일과 비교한다.
  • 만약 이미지가 변경되지 않았다면, 서버는 304 Not Modified 응답을 전송하고, 이를 받은 브라우저는 캐시에 저장된 이미지를 사용하여 로딩 시간을 단축한다.
  • 이미지가 변경되었다면, 서버는 새로운 이미지와 함께 업데이트된 ETag 및 Last-Modified 헤더를 응답으로 전송한다. 브라우저는 새 이미지를 다운로드하고 캐시를 업데이트한다.

🐳 결론

웹 서비스 캐시는 사용자 경험과 서버 성능 향상에 중요한 역할을 한다. 캐시의 생명주기, 유효기간 설정, 재검증 과정을 이해하고 적절한 캐시 관리 전략을 수립하는 것이 중요하다. Etag, Cache-Control 및 파일 버전번호를 함께 사용하면 효율적으로 캐싱할 수 있다

참고 : https://toss.tech/article/smart-web-service-cache


Written by@
기록하는 것을 좋아하는 프론트엔드 개발자👩🏻‍💻

GitHubLinkedIn