[cs] Cache Control 헤더

2025. 8. 13. 21:09·CS 및 기본 개념

Cache-Control의 필요성

문제 상황

다음과 같은 상황에 대해서 생각해보자.

  • 서버는 외부 API를 호출해서 응답 데이터를 생성한다.
  • 서버는 DB에서 데이터를 조회하여 응답 데이터를 생성한다.
  • 서버와 외부 API가 관리하는 데이터는 평균 1시간에 한 번씩 갱신된다.

이러한 상황에서 많은 조회 요청이 발생하면, 서버에 많은 부담과 운영 비용 측면에서 문제가 발생할 수 있다.  

또한, 잦은 외부 API 호출로 인해 많은 비용 발생과 서버 부담이 발생할 수 있다.

 

이러한 상황에서 어떻게 위 문제를 해결할 수 있을까?


방법 1 : Redis와 같은 저장소에 캐싱

해당 방법은 위 문제를 해결할 수 있는 강력한 방법이다.

 

DB에서 조회한 데이터를 빠른 접근이 가능한 캐시에 임시로 저장하기에 DB 서버의 부담을 줄이고 응답 속도를 향상시킨다.

또한, 외부 API 응답 데이터를 캐싱하여 응답 속도를 향상시키고 비용을 감소시킬 수 있다.

 

하지만 이 문제는 서버에 요청이 집중되는 근본적인 문제를 해결할 수는 없다.


방법 2 : Cache-Control 헤더 사용

이러한 상황에서 사용할 수 있는 방법은 Cache-Control 헤더를 사용하는 것이다.

캐시를 사용한다면 HTTP 요청으로 리소스를 origin 서버에서 받아오려고 할 때, 요청을 보내는 대신 저장해둔 응답을 꺼내서 사용한다

 

따라서 위 상황에서 서버에 요청이 집중되는 문제를 어느정도 보완할 수 있다.

또한, Redis와 함께 사용한다면 서버의 부담을 매우 크게 줄이는 역할을 할 수 있다.

 

이번에는 이러한 Cache-Control에 대해서 보다 자세히 알아본다.

 


Cache-Control 헤더

Request의 Cache-Control 속성들

  • no-cache : 요청을 캐시 저장소에 저장하지만, 매번 재검증을 해야함
Cache-Control: no-cache

 

  • no-store : 요청을 캐시 저장소에 저장하지 않고 매번 새로 요청함
Cache-Control: no-store

 

  • max-age=N : 캐시 데이터가 N초 이내에 저장된 데이터라면, 재검증 없이 해당 데이터를 바로 사용
Cache-Control: max-age=60

 

  • max-stale=N : 만료된 캐시 데이터를 N초 동안은 추가로 사용할 수 있도록 함
    • 응답이 느리거나 서버가 죽은 경우 사용하면 좋다.
Cache-Control: max-stale=3600

 

  • min-fresh=N : 캐시 데이터가 만료까지 N초 이상 남은 경우, 재검증 없이 해당 데이터를 사용
    • 요청시 클라이언트가 오랜 시간 갱신되지 않은 데이터를 받는 것을 막을 수 있다.
Cache-Control: min-fresh=600

 

  • no-transform : 아래 응답의 no-transform과 동일함
Cache-Control: no-transform

 

  • only-if-cached : 만료되었더라도 오직 캐싱된 응답만을 반환
    • 만약 저장된 캐시 데이터가 없다면 504 에러를 반환함
Cache-Control: only-if-cached

 

  • stale-if-error : 원본 서버가 오류를 반환하면, 캐시된 데이터를 사용함
Cache-Control: stale-if-error=30

Response의 Cache-Control 속성들

  • max-age=N : 최대 N초동안 응답을 캐시에 저장한다.
    • N초 동안 재검증없이 캐시의 데이터를 사용할 수 있음
Cache-Control: max-age=N

 

  • s-maxage=N : 응답을 최대 N초동안 공유 캐시(CDN 등)에 저장한다.
Cache-Control: s-maxage=N

 

  • no-cache : 응답을 캐시 저장소에 저장하지만, 재사용하기 전 유효성 검사를 해야 한다.
Cache-Control: no-cache

 

  • no-store : 캐시를 저장하지 않기에 매번 요청 시 서버에서 새로운 데이터를 받아와야 한다.
Cache-Control: no-store

 

  • must-revalidate : 응답을 캐시에 저장하고, 최신 상태인 경우에만 재사용 가능함
    • 따라서 응답이 만료되면 재사용 전에 유효성 검사를 하기에 만료된 데이터를 사용하지 않는다.
    • 아래처럼 max-age와 함께 사용하면 만료 후 매번 새로운 데이터를 받아온다.
Cache-Control: max-age=60, must-revalidate

 

  • proxy-revalidate : 공유 캐시에만 적용되는 must-revalidate
Cache-Control: max-age=60, proxy-revalidate

 

  • private : 응답이 브라우저와 같은 private cache(개인 캐시)에만 저장될 수 있다.
Cache-Control: max-age=60, private

 

  • public : 응답이 공유 캐시와 개인 캐시에 모두 저장될 수 있다.
Cache-Control: max-age=60, public

 

  • must-understand : must-understand 뒤에 나오는 옵션들을 현재 환경에서 이해할 수 있어야 캐싱할 수 있다.
    • 아래는 현재 환경에서 max-age와 public을 사용할 수 있을 때 응답을 캐싱할 수 있다.
Cache-Control: must-understand, max-age=60, public

 

  • no-transform : 트래픽 중개자(프록시, CDN 등)가 콘텐츠를 변환해서는 안된다.
    • 일부 프록시는 성능 최적화를 위해서 콘텐츠를 변경하기도 하는데, no-transform은 이를 막는다.
Cache-Control: no-transform

 

  • immutable : 응답이 최신상태일 동안 업데이트되지 않는다.
    • 응답이 만료되기 전까지 불필요한 재검증을 방지하는 역할을 한다.
Cache-Control: max-age=60, immutable 

 

  • stale-while-revalidate=N : 캐시 재검증을 수행하는 동안, 오래된 응답을 재사용한다.
    • 이는 캐시 재검증으로 인한 지연 문제 완화 효과를 갖는다.
    • 아래의 경우, 응답 만료 후 30초동안은 유효성 검사를 하고 있다면 만료된 응답을 사용할 수 있다.
Cache-Control: max-age=60, stale-while-revalidate=30

 

  • stale-if-error=N : 서버나 로컬에서 5xx 오류가 발생한 경우, N초동안 만료된 응답을 재사용할 수 있다.
    • 아래는 응답 만료 후 서버 오류 발생 시 30초동안 만료된 응답을 재사용할 수 있다.
Cache-Control: max-age=60, stale-if-error=30

 


캐시 재검증 ( 유효성 검사 )

캐시 유효성 검사

기본적으로 캐시 재검증시 이전의 데이터와 최신 데이터 간 변경점이 있는지 확인한다.

만약 변경점이 없다면 304 Not Modified 응답을 반환하고, 있다면 200 OK + 최신 데이터를 반환한다.

 

즉 캐시 유효성 검사 중 최신 데이터를 조회하는 연산은 필수적으로 발생한다.

다만, 304 응답을 반환한다면 응답의 전송 비용을 줄일 수 있는 효과를 갖는다.

 

캐시 유효성 검사는 주로 ETag 헤더를 사용하거나, Last-Modified 헤더를 사용하여 검증한다.


ETag + If-None-Match 기반의 캐시 유효성 검사

ETag는 응답 데이터로 구한 해시값을 갖는 태그이다.

해당 태그를 통해 서버는 최신 데이터와 캐싱된 데이터를 효과적으로 비교할 수 있다.

 

주로 ETag와 If-None-Match 헤더를 통해 다음과 같이 진행된다.

  1. 서버가 응답 시 응답 헤더의 ETag에 최신 데이터 해시를 넣어서 반환
  2. 클라이언트가 유효성 검사시 요청 헤더의 If-None-Match에 이전에 받았던 해시를 넣어서 전송
  3. If-None-Match와 최신 데이터 해시가 같다면 304, 다르다면 200+최신 데이터를 반환

해당 방식의 장점과 단점은 다음과 같다.

  • 장점 : 바이트 단위의 정밀한 검증이 가능
  • 단점 : 상대적으로 무거운 해시 연산이 필수임

Last-Modified + If-Modified-Since

ETag와 마찬가지로 데이터가 변경되었는지 확인하기 위한 헤더이다.

다만 ETag는 해시값을 기반으로 작동하고, Last-Modified는 날짜를 기반으로 동작한다.

 

동작 원리는 다음과 같다.

  1. 서버가 응답 시 응답 헤더의 Last-Modified에 데이터 수정 시간을 넣어서 반환
  2. 클라이언트는 유효성 검사시 요청 헤더의 If-Modified-Since에 이전 Last-Modified를 넣어서 전송
  3. If-Modified-Since와 최신 데이터의 수정 시간이 같다면 304, 다르면 200+최신 데이터를 반환

해당 방식의 장점과 단점은 다음과 같다.

  • 장점 : 계산이 간단하고 비용이 적음
  • 단점 : 시간 단위 비교이므로 정밀도가 떨어짐

 


마무리

이번에는 브라우저 기반의 캐싱을 가능하게 해주는 Cache-Control에 대해서 알아보았다.

 

클라이언트 입장에서 Cache-Control은 요청 시 브라우저 캐시를 재사용하므로 서버 부담을 줄이고 응답 속도를 향상시킨다.

다만, 이 때 데이터의 특성에 맞게 적절한 만료 시간을 설정해야 한다.

 

이러한 Cache-Control은 Redis와 함께 사용했을 때 그 효과가 배가 된다.

Redis는 DB나 외부 API에 대한 결과를 임시 저장할 수 있는데, 이는 이러한 무거운 작업 횟수를 줄이는 역할을 하기에 효과적이다.

 

따라서 현재 서비스의 상황에 따라서 적절한 캐싱 전략을 세우는 것이 중요할 것이다.

'CS 및 기본 개념' 카테고리의 다른 글

[ Java 공식문서 ] Lock과 Executor  (1) 2025.08.20
[Java 공식문서] 불변 객체  (4) 2025.08.15
[ Java 공식문서 ] Liveness와 Guarded Block  (6) 2025.08.11
[cs] AWS lambda 기반의 Webhook  (1) 2025.08.07
[ Java 공식문서 ] Java 동시성 프로그래밍 2 : Synchronized  (4) 2025.08.06
'CS 및 기본 개념' 카테고리의 다른 글
  • [ Java 공식문서 ] Lock과 Executor
  • [Java 공식문서] 불변 객체
  • [ Java 공식문서 ] Liveness와 Guarded Block
  • [cs] AWS lambda 기반의 Webhook
코드래곤
코드래곤
코드래곤 님의 블로그 입니다.
  • 코드래곤
    코드래곤 님의 블로그
    코드래곤
  • 전체
    오늘
    어제
    • 분류 전체보기 (61)
      • 알고리즘 (3)
        • 그리디 (1)
        • 그래프 (2)
      • 시스템 설계 (6)
      • CS 및 기본 개념 (17)
      • Docker (5)
      • Spring (23)
        • 백준 서비스 구현하기 (1)
        • 기초 개념 (14)
        • MSA (2)
        • JPA (1)
      • Dart (3)
      • Flutter (1)
      • Kubernetes (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
코드래곤
[cs] Cache Control 헤더
상단으로

티스토리툴바