웹을 사용하다 보면 이미지, CSS, JavaScript 파일을 반복해서 다운받는 경우가 많다.
매번 서버에 요청하고 대기하는 것은 시간과 자원의 낭비이다.
캐시는 이런 문제를 해결하기 위해 등장한 기술로, 웹 성능 최적화의 핵심이다.
캐시의 동작 원리부터 고급 활용법까지 어떤 식으로 이루어지는지 알아보자.
참고로 Cash가 아니라 Cache이다.
왜 캐시를 사용할까?
네트워크 병목 현상
- 문제: 매번 서버에서 데이터를 가져오면 네트워크 대기 시간이 발생한다.
- ex) 1MB의 이미지를 다운로드하는 데 0.5초가 걸린다면 10번 요청했을 경우 5초가 소요된다.
- 해결: 캐시를 사용하면 첫 번째 요청 이후엔 로컬 저장소에서 바로 데이터를 가져온다.
트래픽 비용 절감
- 문제: 대용량 콘텐츠(동영상, 이미지)를 반복 전송하면 서버 트래픽 비용이 급증한다.
- 해결: 캐시로 인해 동일 데이터의 중복 전송을 방지한다.
사용자 경험 개선
- 문제: 로딩 시간이 길면 사용자가 이탈한다.
- 해결: 캐시를 통해 즉시 렌더링이 가능하다.
캐시의 기본 동작
캐시가 없는 경우엔?
먼저 첫 번째 요청을 해보자.
GET /star.jpg HTTP/1.1
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 34012
[이미지 데이터]
- 서버에서 1.1MB 데이터를 전송받는다.
- 브라우저는 이를 렌더링하고 캐시에 저장하지 않는다.
두 번째 요청이 오면 똑같은 1.1MB를 다시 다운로드 한다.
결과적으로 네트워크 낭비 + 느린 속도를 초래한다.
캐시가 적용됐다면?
다시 첫 번째 요청을 해보자.
HTTP/1.1 200 OK
Cache-Control: max-age=60
Content-Length: 34012
[이미지 데이터]
- max-age=60을 통해 60초 동안 캐시가 유효하다는 것을 알린다.
- 브라우저는 이 응답을 캐시에 저장하는 것이다.
60초 이내에 두 번째 요청이 왔다면 캐시에서 직접 데이터를 가져오고 네트워크 사용량은 0MB가 되는 것이다.
캐시 유효 시간이 초과됐다면?
60초 후에 요청을 했다고 치자. 캐시가 만료되겠지?
만료가 되면 서버에 다시 요청을 한다.
여기서 두 가지 가능성이 있다.
조건부 요청이라고 한다(If-Modified-Since 또는 If-None-Match) .
- 데이터 변경이 없다 -> 304 Not Modified (헤더만 전송)
- 데이터 변경이 있다 -> 200 OK (새 데이터 전송)
조건부 요청 헤더
- If-Modified-Since
GET /star.jpg
If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT
- 서버의 데이터가 이 시간 이후로 변경되었는지 확인한다.
- If-None-Match (ETag)
GET /star.jpg
If-None-Match: "686897696a7c876b7e"
- ETag 값이 일치하지 않으면 새 데이터를 받는다.
304 Not Modified 응답
HTTP/1.1 304 Not Modified
Cache-Control: max-age=60
Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT
- 바디 없이 헤더만 전송한다 -> 트래픽 0.1MB 절약.
- 캐시 유효 시간을 재설정한다.
검증 헤더: Last-Modified vs ETag
Last-Modified
- 동작: 파일의 최종 수정 시간을 기준으로 캐시를 검증한다.
- 단점
- 1초 미만 단위는 관리가 불가하다.
- 파일 내용은 같아도 수정 시간이 바뀌면 캐시 무효화가 일어난다(ex: 메타데이터 변경).
ETag (Entity Tag)
- 동작: 파일 내용의 해시 값을 사용한다.
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
- 장점
- 1바이트라도 변경되면 ETag 값이 달라진다.
- 서버가 캐시 정책을 완전히 제어할 수 있다.
- ex) 배포 시 모든 ETag를 갱신해 강제로 캐시 업데이트.
프록시 캐시와 CDN
문제 상황을 만들어보자. 한국 사용자가 미국 서버에 접근하면 500ms의 지연이 발생한다.
어떻게 해결할까?
바로 한국에 프록시 캐시 서버를 두고 공용 캐시로 활용하는 것이다.
Cache-Control: public, s-maxage=3600
- 여기서 s-maxage를 통해 프록시 캐시에만 적용되는 유효 시간을 설정한다.
프록시 캐시를 활용한 기술 중 널리 활용되는 것이 있는데 바로 CDN이다.
Cloudflare와 Akamai 같은 플랫폼이 있다.
CDN의 동작 방식
- 전 세계에 분산된 캐시 서버를 통해 콘텐츠를 저장한다.
- 사용자는 가장 가까운 서버에서 데이터를 받는다.
- 원 서버 부하 분산 + 지연 시간 감소.
캐시 무효화
민감한 데이터는 캐시에 남기는 것이 좋을까? 당연히 그러면 안된다.
이를 막기 위한 여러 지시어가 있다.
no-cache
Cache-Control: no-cache
- 캐시를 사용하기 전에 항상 서버 검증이 필요하다.
no-store
Cache-Control: no-store
- 캐시에 저장 조차 하지 않는다. ex) 개인 정보
must-revalidate
Cache-Control: must-revalidate
- 캐시 만료 후 첫 요청 시 무조건 서버 검증을 한다.
- 서버 접근 실패 시 504 Gateway Timeout 오류를 반환한다.
Pragma와 Expires (레거시 지원)
- Pragma: no-cache: HTTP 1.0 호환을 위한 설정이다.
- Expires: 절대 시간으로 캐시 만료일을 지정한 (예: Expires: Tue, 28 Feb 2023 10:30:00 GMT).
- Cache-Control: max-age가 더 현대적이고 유연하다.
캐시에 대해 포스팅하면서 이해가 많이 되었다.
처음엔 복잡해 보일 수 있지만 원리를 이해하고 전략을 세우는 연습을 하다보면 웹 애플리케이션 성능을 엄청나게 끌어올릴 수 있을 것이다. 여러 캐시 전략을 더 공부해봐야겠다. 앞으로도 파이팅!
'Network' 카테고리의 다른 글
네트워크 관리사 2급 서브넷팅, 라우터 문제 풀어보기 (1) | 2024.11.05 |
---|---|
방화벽의 발전 과정 (6) | 2024.10.01 |
패킷의 생성 원리와 캡슐화 (4) | 2024.08.23 |
NAT란 무엇일까? (46) | 2024.08.09 |
프록시의 구조와 작동원리 (37) | 2024.07.28 |