티스토리 뷰
배경
예전에 웹 서비스 캐시 똑똑하게 다루기 라는 글을 읽었다. 과연 똑똑하게 다루는 방법은 뭘까? 지금 내가 하는 프로젝트는 어떤 방법을 사용해야할까? 타사 서비스들은 어떻게 다루고 있을까? 이런 여러가지 고민들을 했고 정리해보려고 한다.
기초 지식
캐시 컨트롤에 대한 기초 내용은 다루지 이 글에서 다루지 않습니다. 다만 필수적인 내용만 가볍게 정리하고 넘어갑니다.
no-cache: 브라우저(로컬) 캐시를 사용하지 않는다. 단, cdn(중간서버) 캐싱은 사용한다.(사용 전 서버에 재검증)
no-store: 모든 캐시(브라우저, cdn)를 사용하지 않는다.
max-age: 브라우저 캐시 유지 시간
s-max-age: cdn 캐시 유지 시간
public: 브라우저와 중간 서버가 모두 캐시를 저장할 수 있음
private: 가장 끝의 사용자 브라우저만 캐시를 저장할 수 있음
본론
웹에서는 여러가지를 네트워크로 불러오기 때문에 캐시컨트롤을 조금 카테고리를 나눠서 적어보겠다.
새로고침
새로고침을 하면 조금 특이한 동작을 한다. (브라우저마다 동작이 다르다. 일단은 크롬만 알아보자.
html파일에 대해 요청 헤더의 cache-control에 max-age=0을 추가한다. 그렇기 때문에 브라우저 캐시가 적용되지 않는다.
브라우저가 이렇게 동작하는 이유는 사용자의 의도를 존중하기 위함이다. 사용자가 새로고침 버튼을 누르는 행위는 "최신 콘텐츠를 보여달라"는 명시적인 요청으로 해석된다. 이때 브라우저는 요청 헤더에 max-age=0을 추가함으로써 서버에게 "이 자원이 아직 유효한지 확인해달라"고 요청한다.
서버는 이에 대해 두 가지 방식으로 응답할 수 있다
1. 콘텐츠가 변경되었다면 새 콘텐츠와 함께 200 상태 코드 반환
2. 콘텐츠가 동일하다면 본문 없이 304 Not Modified 상태 코드 반환 (네트워크 트래픽 절약)
이는 사용자 경험과 네트워크 효율성 사이의 균형을 맞추는 똑똑한 메커니즘이다.
강력 새로고침을 하면 cache-control에 no-cache, Pragma에 no-cache를 추가한다. 이 경우 서버는 무조건 완전한 응답을 반환해야 하며, 304 응답도 허용되지 않는다.
개발자 도구 캐시 사용중지
요청 헤더의 cache-control에 no-cache가 추가된다. 이건 꽤 중요한 부분이라서 인지해야한다. 밑에서 구체적인 예시로 추가 설명하겠다.
CDN 기본 옵션
공식문서: 배포의 캐시 정책을 업데이트하여 캐시 기간을 관리하는 것이 좋습니다. 캐시 정책 사용을 옵트아웃하는 경우 기본 TTL(Time to Live)은 24시간이지만 다음 설정을 업데이트하여 기본 설정을 재정의할 수 있습니다.
캐싱이 적용되지 않는 것은 그나마 작은 문제이지만 위 기본설정으로 인해 잘못된 캐싱이 적용되는 것은 큰 문제다. 그렇기 때문에 cache-control의 세부적인 사용법 숙지와 설정은 필수다.
html
html에는 보통 `no-cache, no-store, must-revalidate`를 가장 많이 사용한다. (경우에 따라 max-age=0을 적용하기도 한다.)
위 코드를 빼먹으면 치명적인 버그가 생길 수 있다. 필수다.
가끔 s-max-age를 사용하는 곳도 보인다.
정적 웹사이트의 경우에는 cdn 캐싱과 invalidate를 활용하면 캐싱을 조금 더 활용할 수 있는데 생각보다 많이 사용되지는 않는 것 같다.
아마 대부분 웹사이트들의 html 용량이 크지 않고 유의미한 차이가 없어서 그런것같다.
예시
N사 메인 웹사이트
`no-cache, no-store, must-revalidate`
가장 일반적인 방법이다.
T사의 메인 웹사이트
`s-maxage=31536000, max-age=0`
네트워크탭을 확인해보니 cdn 캐싱을 사용해 304가 뜨고 불러오는 용량에 차이가 있지만 실제 네트워크 시간은 거의 동일하다.
(오히려 DNS 캐싱시간의 차이가 훨씬 크다.)
A사의 메인 웹사이트
`private, max-age=120`(max-age는 120에서 0 사이의 값이다.)
굉장히 특이한 방식을 사용한다. 새로고침을 하면 이전 시간에서 현재시간을 뺀만큼 줄어든 max-age값이 보인다.
html은 정~~말 변경되지 않는다는 확신이 없다면 브라우저 캐시를 사용하면 안된다. html은 url입력시에 처음 나타나는 부분이기 때문에 변경이 어렵다.
하지만, 그렇다고 용량이 큰 html 파일에 대해 몇 초의 캐싱도 사용하지 않는 것은 비효율적이다. 그래서 위의 방법을 사용하는 것 같다.
js, css
이 경우에 브라우저 캐싱은 좀 조심해야한다.
만약 파일 내용이 변경되었는데 브라우저 캐싱이 적용되어있다면 유저는 변경된 사항을 볼 수 없다.
이 경우에는 여러가지 해결방법이 있다.
1. 짧은 브라우저캐싱과 cdn 캐싱 사용하기
이 짧은 브라우저캐싱은 굉장히 조심해야되는 포인트다. 배포했는데 만명의 유저가 버그를 겪었고 1시간 캐싱이라면 바로 롤백을 한다고 해도 이는 만명의 한시간 장애로 이어진다.
2. 매번 다른 파일로 올리기
과거의 웹을 기준으로 한다면 어렵다. 매번 파일이름을 변경하는건 불가능에 가깝다고 본다.
다만 지금은 번들러를 사용하고 고유한 네이밍을 붙일 수 있기 때문에 어렵지 않다. 하지만 그로 인해 배포할 때마다 모든 파일의 캐싱은 사라지게 된다. 이걸 해결하기 위한 방법은 꽤 복잡해서 별도의 글을 작성하겠다.
3. 캐싱 전혀 사용하지 않기
용량이 크지 않은 파일들이라면 그냥 캐싱을 사용하지 않는 것도 방법이다. 최선은 아니지만 최악을 맞는것도 상황에 따라 좋은 선택이다.
4. 변경되지 않는다고 확신이 드는 경우 캐시 컨트롤을 길게 적용하고 만약 변경이 필요하면 새로운 파일로 올리기
이것도 생각보다 많이 사용하는 방식이다. 다만 주의해야한다.
5. 계층 만들기
A 스크립트: 로더 역할, 항상 같은 이름 유지, 캐싱 없음
B 스크립트: 실제 무거운 콘텐츠 포함, 변경 시 파일명 변경, 장기 캐싱 적용
A는 가볍기 때문에 캐싱없이도 금방 불러오고 B는 캐싱을 통해 빠르게 불러올 수 있다.
이미지, 동영상
너무 다양하다. 1일, 1주일, 한달, 1년 등등 상황에 따라 적절한 브라우저 캐시를 사용한다. 가장 많이 사용하는 건 그래도 1주일인 것 같다.
폰트, favicon
폰트와 favicon은 거의 변경될일이 없다. 그렇기 때문에 s3 + cdn + max-age=31536000 을 적용하자.
만약 폰트와 favicon이 변경되어야한다면 파일이름을 변경하는걸 잊지말자.
모든 이들이 cache-control에 대해 익숙하지는 않기 때문에 문서화와 공유는 필수다.
아이콘
svg로 아이콘을 관리하는 경우가 많다. 그런데 아이콘은 이미지에 비해 변경될 확률이 높다.(팀에 따라 다를 수 있음)
그렇기 때문에 함부로 브라우저 캐시를 적용할 수 없다.
이걸 해결하기 위해서는 굉장히 다양한 방법이 있다. 레퍼런스도 몇가지 봤고 내가 좋다고 생각하는 방식도 있다.
몇가지만 간단하게 언급하고 넘어가겠다.
- 번들러에 포함하기
번들러에 포함하면 배포할 때마다 모든 캐싱이 무효화되지만 그래도 배포이전까지는 캐시 사용이 가능하다.
- 짧은 브라우저캐싱과 cdn 캐싱 사용하기
아이콘 변경은 잠깐 잘못노출되어도 심각하지는 않기 때문에 이것도 방법이다.
- 버전관리, 파일 diff, 쿼리파람 활용하기
s3에 중복된 이름을 허용하면서 변경된 파일만 캐싱을 무효화하려면 쿼리파람을 붙이면 된다. 쿼리파람이 달라지면 같은 url도 다르게 인식하기 때문에 새로운 아이콘을 불러온다.
후기
프론트 개발자로 취업한지 3년이 지났는데 이제야 이런것들을 신경쓰기 시작했다니 좀 부끄럽다는 생각과, 이제라도 알아서 다행이라는 생각이 든다.
'기술' 카테고리의 다른 글
큐(queue) 실무에서 사용하기(스크립트, 인증) (3) | 2025.03.21 |
---|---|
추상화 > 카테고라이즈 실무에서 적용하기(enum) (0) | 2025.03.19 |
타사 제품 분석해보기(네이버 쇼츠, 유튜브 쇼츠) (1) | 2025.03.11 |
useState, useEffect, useRef 만들기(feat. 클로저) (1) | 2025.02.27 |
비동기 함수 효율적으로 처리하기 (0) | 2025.02.12 |