Skip to content

Commit

Permalink
Post: HTTP 캐시 글 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
yiyb0603 authored Nov 2, 2023
2 parents 072eab0 + af1fe8e commit 18262a2
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 1 deletion.
169 changes: 169 additions & 0 deletions posts/useful-http-cache.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
---
title: 자주 사용되는 HTTP 캐시 옵션 알아보기
description: 웹 서비스에서 자주 사용되는 HTTP 캐시 옵션에 대해서 알아봅시다.
category: Develop
createdAt: 2023-11-02
thumbnail: https://github.com/yiyb0603/yiyb-blog/assets/50941453/c04ef50d-f878-4a7d-8dfc-a2dccc195929
---

안녕하세요! 오늘은 웹 서비스에서 자주 사용되는 `HTTP 캐시` 옵션에 대해서 알아보도록 하겠습니다.

<br />

이전 그리고 최근에 AWS의 CloudFront를 건드리는 일이 많았었는데, 이를 통해서 알게된 내용들을 정리해보도록 하겠습니다.

## 1. 캐시의 중요성 🚀

먼저 캐시란 시스템에서 **데이터나 정보를 임시로 저장하는 공간**을 의미합니다. 이는 이전에 가져온 데이터에 대해 기억하고, 이후 동일한 결과에 대해서 재연산없이 캐시에서 값을 가져와서 작업을 빠르게 처리할 수 있도록 도와줍니다. 즉 캐시는 **시스템의 불필요한 연산을 없애고, 성능을 향상시키는 역할**을 합니다.

<br />

웹 서비스에서는 어떤것들이 캐싱의 대상이 될까요? 바로 **네트워크를 통해 다운로드 되는 모든 리소스들**이 대상이 됩니다. 대표적으로 `HTML/CSS`, `자바스크립트`, `폰트/이미지` 파일들이 `리소스`에 해당됩니다.

<br />

이중에서 특정 리소스는 거의 내용이 바뀌지 않는데, 다른 리소스는 웹 페이지를 불러올때마다 내용이 변경될 수 있는 리소스들도 있습니다. 그래서 이를 `HTTP 캐시`를 사용하여 제어할 수 있는데요. 이를 밑 섹션에서 자세하게 알아보겠습니다.

## 2. HTTP 캐시 옵션 📗

기본적으로 리소스에 대해 `HTTP 캐시`를 지정하려면 `Cache-Control` 헤더를 통해서 지정할 수 있습니다. 그렇다면 이 `Cache-Control` 헤더에는 어떤 값들을 담을 수 있을까요?

> http 1.0 하위 호환을 위해서 `Pragma`라는 헤더도 같이 사용하는 경우도 있습니다. (Cache-Control과 동일한 역할)
### 2-1. max-age

`max-age` 속성은 해당 리소스를 언제까지 `브라우저 캐시`에 저장해둘것인지를 지정하는 속성으로, 가장 대표적인 HTTP 캐시 속성이기도 합니다. 브라우저에서 캐시의 만료여부를 확인할때는 `max-age`의 값을 통해서 검증하기에 캐싱에 필수적입니다.

```json
{
"Cache-Control": "max-age=3600"
}
```

`max-age`는 초 단위로 지정을 해주어야 하는데요. 만약 위 코드처럼 3600 이라는 값을 넣는다면 브라우저는 3600초(1시간)가 지나기 전까지 저장된 캐시를 사용합니다.

<br />

만약 `max-age`로 설정한 시간이 지난경우에는 어떻게 동작할까요?

브라우저에서 캐시를 재검증했을때 새로운 값과 캐시가 같다면 `304 Not Modified` 응답을 받을 수 있습니다. 304 응답을 받았을때는 **매우 적은 리소스**(몇백 바이트 단위) 를 네트워크로 내려받기에 속도 측면에서 이점을 가집니다.

그러나 이전 캐시와 새로운 값과 다를경우에는 처음 리소스를 다운받을때와 동일하게 원본 용량을 네트워크로 다운받게 됩니다.

> 이전 캐시와 새로운 값을 검증할때 브라우저에서는 `If-None-Match`
### 2-2. If-None-Match, If-Modified-Since

`max-age`로 지정한 시간이 지났을때 브라우저에서는 두 리소스가 동일한지 검증하는 절차를 진행하는데, 이 두개의 속성을 통해서 브라우저가 검증을 하게됩니다.

> 브라우저에서 검증시 자동으로 속성이 들어갑니다.
`If-None-Match`는 리소스의 `ETag` 속성이 같은지 검증하는데요. `ETag`란 간단하게 말해서 리소스를 해싱한 문자열 값이라고 생각하시면 됩니다. 리소스 내용이 변경되면 해싱 내용도 변경되기에 브라우저가 검증을 할 수 있습니다.

<br />

`If-Modified-Since`는 리소스의 `Last-Modified` 속성이 같은지 검증하는데요. `Last-Modified`는 리소스가 마지막으로 수정된 시간을 나타낸 값인데요. 리소스 내용이 수정되었을때 해당 값이 변경되므로 브라우저가 검증을 할 수 있습니다.

### 2-3. s-maxage

`s-maxage` 속성은 위의 `max-age`와 유사하지만 한가지 다른점이 있습니다. `max-age`는 브라우저에서 캐시를 저장하는 시간이지만 `s-maxage`**중간 서버**에서 캐시를 저장하는 시간입니다.

주로 원본 서버(Origin Server)에서 사용됩니다.

![브라우저, 중간서버, 원본서버 관계도](https://github.com/yiyb0603/yiyb-blog/assets/50941453/6bf6f934-8779-4fcf-ad36-4c2e21ca9614)

<br />

**중간 서버**란, 리소스가 저장되어있는 `원본 서버(Origin Server)``브라우저` 사이에 위치한 서버인데요. 가장 대표적인것이 `CDN` 서버입니다. CDN 서버는 어느곳에서나 접속하는 사용자들에 대해 물리적으로 가까운 서버에서 응답을 줄 수 있고, 원본 서버에서 가져온 리소스를 캐싱할 수 있기에 최근 웹 서비스에서는 필수적으로 사용됩니다.

<br />

CDN과 같은 중간서버에서도 언제까지 캐시를 저장할지에 대한 속성이 바로 `s-maxage` 입니다.

```json
{
"Cache-Control": "s-maxage=3600"
}
```

### 2-4. no-cache

`no-cache` 속성은 사용하려는 리소스를 캐시에 저장 가능하되, 항상 서버에 재검증 요청하도록 지정하는 속성입니다. 즉 `304 Not Modified` 응답을 받은 경우에만 리소스를 사용할 수 있습니다.

저는 처음에 이름을 들었을때는 캐싱을 완전히 안하겠다라는 뜻인줄 알았는데 아니더라고요.

```json
{
"Cache-Control": "no-cache"
}
```

> 눈치채신분들도 있겠지만, `no-cache``max-age=0`과 동일한 의미를 가집니다.
### 2-5. no-store

`no-store` 속성은 리소스를 절대로! 캐시에 저장하지 않도록 지정하는 속성입니다. **주로 민감한 리소스를 다룰때 사용됩니다.** `no-cache` 속성은 리소스가 같을때는 적은량의 네트워크를 수신받지만, `no-store` 속성은 항상 원본용량의 네트워크를 수신받는 차이가 있습니다.

```json
{
"Cache-Control": "no-store"
}
```

### 2-6. must-revalidate

`must-revalidate` 속성은 캐시가 만료되고 재검증 요청을 했을때 **만약 원본 서버(Origin Server)에서 오류가 발생한경우 타임아웃을 발생시킵니다.**

<br />

만약 `must-revalidate` 속성이 없다면 원본 서버에서 오류가 발생한경우 **중간서버**는 이전 캐시를 다시 사용하게 됩니다. 만약 이전 캐시를 사용하는것을 원치않고, 오류를 발생시키는것을 원한다면 `must-revalidate` 속성을 사용해야 합니다.

```json
{
"Cache-Control": "max-age=6000, must-revalidate;"
}
```

## 3. 실제로 사용해보기 🔨

그렇다면 웹 서비스에서 이러한 캐시 속성들을 언제, 어떻게 사용할 수 있을까요? `Next.js`로 만들어진 웹 서비스에서 저는 아래와 같이 사용하고 있습니다.

### 3-1. HTML 파일

HTML 파일은 항상 동일한 URL을 가지고 있기 때문에 내용이 변경되는 타이밍을 예측하기 어렵습니다. 그렇기에 항상 사용하려고 할때마다 재검증을 요청하는 `no-cache`를 지정합니다.

### 3-2. CSS, JS 파일

![항상 고유한 URL을 가진 CSS, JS 파일](https://github.com/yiyb0603/yiyb-blog/assets/50941453/2a1c91d3-825f-4640-9a2b-5237072c40e8)

Next.js에서 빌드를 하고나면 모든 **CSS, JS 파일들은 고유한 URL**을 가지고 있기 때문에 배포를 통해서 교체되면 URL이 자동으로 변경되어 새로운 캐시가 생성됩니다. CSS와 JS 파일은 절대 변경될 수 없는 캐시라고 생각하고 넉넉한 `max-age (약 1년)`를 지정합니다.

### 3-3. 이미지/폰트 파일

이미지와 폰트 파일 또한 내용이 변경된 경우에는 대부분 해당 파일의 URL이 변경될 수 있지만, 그렇지 않은 경우를 대비해서 `no-cache`를 지정해두고 중간서버에서 넉넉하게 `s-maxage (약 1년)`을 지정합니다.

<br />

그러나 만약 이미지 파일의 URL이 변경되지 않고 내용만 변경되었을때 중간 서버의 캐시를 초기화해야 하는데, 이는 어떻게 해결할 수 있을까요?

## 4. CDN Invalidation ♻️

![CloudFront CDN 무효화](https://github.com/yiyb0603/yiyb-blog/assets/50941453/5cab08f5-149a-446b-9c51-cbb079494078)

중간 서버의 캐시를 초기화 하기 위해서 대부분의 CDN에서는 `CDN 무효화(Invalidation)`를 제공하고 있습니다. 대표적인 CDN 플랫폼 `CloudFront`에서도 위처럼 무효화를 지원하는데요. 무효화 하려는 리소스의 경로를 **와일드카드 패턴**으로 지정해줄 수 있습니다.

<br />

예를 들어 `s-maxage`로 캐시를 관리하는 이미지 파일의 URL이 변경되지 않고 내용만 변경된 경우에 이처럼 `무효화`를 통해 중간 서버의 캐시를 초기화 해줄 수 있습니다.

> 그렇다면 `max-age`가 지정된 브라우저 캐시는 어떻게 초기화 하나요?
개발자단에서 사용자의 브라우저 캐시를 초기화 하는것은 불가능합니다. 그래서 `max-age` 속성은 항상 신중하게 고려하여 지정해주어야 합니다.

## 5. 마치며 📌

오늘은 자주 사용되는 HTTP 캐시의 속성들에 대해서 정리해보는 시간을 가졌습니다. 웹 서비스를 운영할때 캐시를 잘 조정하면 리소스를 최적화하여 관리할 수 있기에 정말 좋은 기술이라고 생각합니다.

<br />

여러분들도 HTTP 캐시를 사용하여 리소스를 최적화 할때 많은 도움이 되었으면 좋겠습니다. 이상으로 글을 마치겠습니다. 글 읽어주셔서 감사합니다! 😀
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const SimplePostItem = ({
};

const ThumbnailImage = styled(Image)`
${({ theme }) => theme.device.smallTablet} {
${({ theme }) => theme.device.tablet} {
display: none;
}
`;
Expand Down

0 comments on commit 18262a2

Please sign in to comment.