웹 캐시(Web cache)와 AWS S3, CloudFront

2024-08-21 hit count image

웹 개발에서의 캐시(Cache)에 대해서 알아보고, AWS S3와 CloudFront를 사용하여 정적 파일로 웹 서비스를 제공할 때 캐시를 적용하는 방법에 대해서 알아봅시다.

개요

웹 개발에서 캐시(Cache)는 중요한 역할을 합니다. 캐시를 통해 웹 서비스의 성능을 향상시킬 수 있고, 사용자 경험을 개선할 수 있습니다. 이번 블로그 포스트에서는 웹 개발에서의 캐시(Cache)에 대해서 알아보고, AWS S3에 정적 파일로 웹 서비스를 제공할 때 캐시를 적용하는 방법에 대해서 알아봅시다.

웹 캐시 탄생 배경

클라이언트(PC, 스마트폰)에서 서버에 있는 정보를 습득하기 위해서는 인터넷(Internet)을 사용하게 됩니다.

Web cache and S3 - server and client with internet

클라이언트와 서버를 연결해주는 인터넷은 물리적으로 연결되어 있으며, 전 세계의 인터넷은 해저 케이블로 연결되어 있습니다.

Web cache and S3 - internet submarine cable

클라이언트와 서버는 이렇게 물리적으로 연결이 되어있기 때문에, 당연히 거리가 멀수록 데이터를 주고 받는데 시간이 걸리게 됩니다.

웹 캐시

웹 캐시는 물리적으로 먼 곳에 있는 서버의 콘텐츠 중 변경이 적은 콘텐츠(정적 콘텐츠: HTML, CSS, JS, Image, Video 등)를 물리적으로 가까운 곳(서버)에 복사하여 배치함으로써 데이터 송수신의 지연을 줄이는 기술입니다.

Web cache and S3 - web cache

웹에서는 크게 세가지 캐시를 사용합니다.

  1. CDN(Contents Delivery Network)
  2. 브라우저 캐시(Browser cache)
  3. 데이터베이스 캐시(Database cache)
Web cache and S3 - web cache with browser

이번 블로그 포스트에서는 CDN과 브라우저 캐시에 대해서 알아보도록 하겠습니다.

CDN(Contents Delivery Network)

CDN은 변경이 적은 콘텐츠의 복사본을 세계의 여러 곳에 있는 서버를 두고 콘텐츠를 제공하는 서비스입니다.

이를 통해 클라이언트와 서버 간의 거리를 줄여 데이터 송수신의 지연을 줄일 수 있습니다.

예를 들어, 세계적으로 유명한 CDN 서비스인 Cloudflare는 다음과 같이 전 세계에 서버를 두고 있습니다.

Web cache and S3 - cloudflare server list

Cloudflare를 이용하면 정적 파일을 Cloudflare가 제공하는 서버에 복사하여 클라이언트와 가까운 서버에서 콘텐츠를 제공할 수 있습니다.

브라우저 캐시(Browser cache)

클라이언트 측에서 보면 가장 가까운 서버는 클라이언트 자체입니다. 브라우저는 클라이언트가 한 번 액세스한 사이트에서 일부 콘텐츠를 클라이언트 스토리지에 저장하고 다시 액세스할 때 이 저장된 콘텐츠를 사용하게 하는 브라우저 캐시 기능을 제공합니다.

Chrome 브라우저의 경우 다음 위치에 캐시를 합니다.

  • Windows: C:\Users\<User Name>\AppData\Local\Google\Chrome\User Data\Default\Cache
  • macOS: /Users/<User Name>/Library/Caches/Google/Chrome/Default/Cache

웹 캐시 동작 방식

웹 캐시가 동작하는 방식에 대해서 알아보도록 하겠습니다.

Web cache and S3 - web cache process
  1. 사용자가 브라우저에서 서비스에 액세스합니다.
  2. 브라우저는 브라우저에 캐시된 것이 있는지 확인하고 캐시가 있는 경우 이를 사용하여 화면에 표시합니다.
  3. 브라우저에 캐시가 없으면 CDN에 캐시가 있는지 확인합니다. CDN에 캐시가 있는 경우 캐시를 사용합니다.
  4. CDN에 캐시가 없으면 실제 서버에서 콘텐츠를 가져옵니다.
  5. 이때 CDN은 캐시할 필요가 있는지 확인하고 캐시할 수 있는 경우 캐시합니다.
  6. 브라우저도 마찬가지로 캐시할 수 있는 경우 캐시합니다.
  7. 다음부터 사용자가 같은 콘텐츠에 액세스할 때 브라우저와 CDN에서 캐시된 콘텐츠를 사용합니다.

웹 캐시 설정

브라우저와 CDN은 어떤 기준으로 캐시를 설정할까요? 브라워저와 CDN은 HTTP 응답 헤더에 Expires, Cache-Control, Etag, Last-Modified 등을 확인하여 캐시 여부를 결정합니다.

HTTP 응답 헤더에 캐시는 다음과 같은 방법으로 설정할 수 있습니다.

  • Nginx 설정
server {
    listen 80;
    server_name example.com;

    location / {
        # Set Cache-Control
        add_header Cache-Control "max-age=3600, public";

        # Set Expires
        expires 1h;
    }
}
  • 웹 서버 설정(NodeJS의 Express 예)
const express = require('express');
const app = express();

app.use((req, res, next) => {
    // Set Cache-Control
    res.setHeader('Cache-Control', 'max-age=3600, public');

    // Set Expires
    const maxAgeInSeconds = 3600;
    const date = new Date();
    date.setSeconds(date.getSeconds() + seconds);
    const expiryDate = date.toUTCString()
    res.setHeader('Expires', expiryDate);

    next();
});

app.get('/', (req, res) => {
    res.send('Hello World!');
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

이렇게 설정된 HTTP 응답 헤더를 확인하여 CDN과 브라우저가 캐시를 설정하게 됩니다.

AWS S3와 CloudFront

AWS의 S3와 CloudFront를 사용하여 정적 웹 사이트를 서비스할 수 있습니다.

  • S3(Simple Storage Service): 정적 파일을 저장하는 서비스
  • CloudFront: CDN 서비스

S3는 스토리지 서비스이지만 정적 파일로 웹 서비스를 할 수 있는 서버 기능도 제공하고 있습니다.

일반적으로 HTML, CSS, JavaScript로 개발된 정적 웹 페이지나 React, Vue, Angular 등의 프론트엔드 프레임워크로 개발된 웹 애플리케이션의 빌드 결과물을 S3에 업로드하여 CloudFront를 통해 서비스하게 됩니다.

Web cache and S3 - AWS S3 and CloudFront cache

이때, S3에 업로드한 파일 설정으로 통해 브라우저 캐시와 CDN(CloudFront) 캐시를 설정할 수 있습니다.

AWS S3 캐시 설정

캐시는 HTTP의 응답 헤더에 ExpiresCache-Control을 설정하기 때문에 기본적으로 프론트엔드 측에서 설정할 수 없습니다.

CloudFront + S3는 서버가 없기 때문에 HTTP 헤더를 설정하는 서버 코드를 추가할 수 없습니다.

하지만 S3가 서버 기능을 가지고 있으므로, S3의 설정을 통해 바꾸는 것으로 캐시를 설정하게 됩니다.

AWS가 제공하는 CLI 툴을 사용하여 S3에 파일을 업로드할 때, 다음과 같은 명령어를 사용합니다. 이때, --cache-control 옵션을 사용하면 캐시를 설정할 수 있습니다.

aws s3 cp <Target directory> s3://<S3 Bucket name> --recursive --exclude "assets/*" --cache-control 'public,max-age=60,stale-while-revalidate=2592000’
  • Target directory: S3에 업로드할 빌드 결과가 있는 로컬 폴더 경로
  • S3 Bucket name: 파일을 업로드할 대상이 되는 S3의 Bucket name
  • --recursive 옵션: aws s3 cp는 기본 파일 하나를 복사하는 명령이므로, 지정된 디렉토리의 모든 파일을 업로드하기 위해 --recursive 옵션 사용
  • --exclude "assets/*": 업로드 제외 대상 설정
  • --cache-control 'public,max-age=60,stale-while-revalidate=2592000': 캐시 설정
  • max-age=60: 60초 동안 캐시
  • stale-while-revalidate: max-age에 의해 캐시가 종료된 경우, 백그라운드에서 콘텐츠를 다시 확인하고 캐시하는 동안, 만료된 캐시를 최대 30일 동안 제공하도록 설정

GitHub Actions

다음은 GitHub Actions를 사용하여 S3에 파일을 업로드하는 코드입니다.

- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: $
    aws-region: ap-northeast-1
- name: Upload file to S3
  run: |
    aws s3 rm s3://$ --recursive
    aws s3 cp apps/dist s3://$ --recursive --exclude "assets/*" --cache-control 'public,max-age=60,stale-while-revalidate=2592000'
    aws s3 sync apps/dist/assets s3://$/assets --cache-control 'public,max-age=60,immutable'

aws s3 rm을 사용하여 모든 파일을 삭제한 후, aws s3 cp를 사용하여 파일을 업로드합니다. 마지막에 assets 폴더를 aws s3 sync를 사용하여 업로드합니다.

stale-while-revalidate를 사용한 무중단 배포

AWS에서 소개된 사용법입니다.

stale-while-revalidate를 사용하면 중단없이 서비스 버전을 업데이트할 수 있습니다.

Web cache and S3 - stale-while-revalidate option for no downtime deployment
  1. 사용자가 브라우저에서 서비스를 실행합니다.
  2. V1에서 이미 서비스를 이용하고 있는 유저는, 브라우저에 stale-while-revalidate가 설정된 V1의 캐시가 있으므로, 그것을 우선 사용하게 됩니다.
  3. 브라우저는 백그라운드에서 캐시가 종료된(max-age) 콘텐츠를 CloudFront(CDN)에 요청하게 됩니다.
  4. CloudFront는 V2로 업데이트된 캐시가 있으므로, 그것을 브라우저에 제공합니다.
  5. 브라우저는 CloudFront로부터 전달받은 콘텐츠를 캐시해 다음부터 이것을 사용하게 합니다.
  6. 만약 CloudFront의 캐시도 갱신이 필요한 경우(max-age), 우선은 stale-while-revalidate가 설정된 V1의 캐시를 브라우저에 제공한 후, 백그라운드에서 실제의 서버로부터 콘텐츠를 가져와 자신의 캐시를 갱신합니다.

완료

이것으로 웹 캐시(Web cache)에 대해서 알아보고, AWS S3와 CloudFront를 사용하여 정적 파일로 웹 서비스를 제공할 때 캐시를 적용하는 방법에 대해서 알아보았습니다.

이 블로그 포스트가 웹 캐시의 이해와 AWS에서 웹 캐시를 적용할때 도움이 되었기를 바랍니다.

제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!

앱 홍보

책 홍보

블로그를 운영하면서 좋은 기회가 생겨 책을 출판하게 되었습니다.

아래 링크를 통해 제가 쓴 책을 구매하실 수 있습니다.
많은 분들에게 도움이 되면 좋겠네요.

스무디 한 잔 마시며 끝내는 React Native, 비제이퍼블릭
스무디 한 잔 마시며 끝내는 리액트 + TDD, 비제이퍼블릭
[심통]현장에서 바로 써먹는 리액트 with 타입스크립트 : 리액트와 스토리북으로 배우는 컴포넌트 주도 개발, 심통
Posts