웹 성능 개선과 HTTP Cache
이번 포스팅은, 개인적으로 궁금하기도 한 부분이며, 잘 모르는 부분이기도 하여 스토리텔링 형식으로 정리해볼까 한다.
앞전의 포스팅에서, 웹의 본질은 결국 "Request & Response" 임을 언급했었다. 그렇다면 웹 성능 개선은 어떤 것을 의미할까? 이것 또한 웹의 본질과 연관된다. Request를 보냈을 때 Response를 가능한 빠르게 받아, 웹 페이지의 로드 시간을 단축시킨다. 이것이 곧 웹의 본질과 연결되는 것이다.
웹 브라우저는 매 번 웹 서버에게 Request하여 결과를 받아야하고, 웹 서버는 매 번 웹 브라우저의 Request에 대해 결과를 만들고, Response를 반환해야 한다. 여기서 한 가지 의문점이 발생한다. 웹 페이지의 로드 결과가 똑같다면, (반복된 Request와 Response를 계속해야 한다면) 웹 브라우저는 매 번 웹 서버에게 받아올 필요가 없을 것이다. 반대로, 웹 서버는 매 번 결과를 만들어 웹 브라우저에게 반환할 필요도 없을 것이다.
① 이전에 받았던 결과를 저장하고, 매 번 요청할 때마다 저장해놓은 결과를 재사용 반환하면 되지 않을까?
② 이전에 반환했던 결과를 저장하고, 매 번 요청받을 때마다 저장해놓은 결과를 재사용 반환하면 되지 않을까?
①, ②의 의문점에서 출발한 것이 Cache이다. 정리해보자.
"웹 서버의 부하를 줄이고, 웹 페이지의 로드 성능을 개선하자" → HTTP Cache를 사용하는 이유이다.
조금 더 면밀히 살펴보자.
고양이 동영상을 받아오는 웹 사이트가 있다고 가정해보자. 그 고양이 영상은 너무나도 많아 용량이 100MB에 해당한다고도 가정한다. 웹 브라우저는 매 번 똑같은 100MB 짜리 고양이 동영상을 웹 서버로부터 받아온다.
" 웹 브라우저는 매 번 똑같은 100MB 짜리 고양이 동영상을 웹 서버로부터 받아온다. " 이는 반복의 문제를 야기한다.
반복되는 서버 자원(CPU 및 Memory) 소비 문제가 존재한다. 모든 유저의 요청에 대한 반복된 연산을 진행해야 되기 때문이다.
그렇다면, 이전에 만들어놓았던 100MB짜리 고양이 동영상을 재사용한다면 어떨까?
바로 캐시를 사용하는 것이다. 반복되는 서버자원에 여유가 생겨, 모든 유저의 요청에 대해 간단히 처리 가능하다. 위 그림에서 초록색 라인만 잘 살펴보면 된다. 웹 서버에 있는 빨간색 파일(고양이 동영상)을 경유하지 않고 캐시된 데이터를 불러온다.
정리해보자. 캐시를 사용하면,
1. 반복되는 서버 자원(CPU 및 Memory)에 여유가 생긴다.
2. 불특정 다수의 웹 브라우저에게도 캐시된 자원을 제공할 수 있다.
-> 웹 브라우저의 캐시는 웹 브라우저 유저만 캐시된 자원을 활용할 수 있었다.
캐시를 사용하는 이유와 장점에 대해 간략히 알아보았다. 아니 근데 캐시가 뭔가? 캐시는 사실 정말 폭넓게 쓰이는 용어이다.
⚠️ Cache 캐시 용어의 범용성
|
우리는 현재 "웹 성능 개선"에 대해 다루고 있기 때문에, HTTP Cache를 중점적으로 다룰 것이다.
웹 브라우저와 웹 서버는 반복되는 요청에 대해 부담을 나누기 위해, HTTP Cache를 도입한다. HTTP Cache는 웹 브라우저와 웹 서버사이의 임시 중간 저장소라고 이해하면 된다.
앞서 예시를 들었던 "고양이 동영상을 보여주는 웹 사이트"를 생각하며 위의 그림을 천천히 살펴보자. HTTP Cache는 아래와 같은 결과들을 저장할 수 있을 것이다. Public, Private는 일단 무시하고 넘어가자.
1. 웹 브라우저와 웹 서버 사이 임시 중간 저장소(HTTP Cache)에 재활용하려는 고양이 동영상(결과)를 저장한다.
2. 웹 브라우저와 웹 서버 사이 임시 중간 저장소(HTTP Cache)에 재활용하려는 동적 웹 페이지(결과)를 저장한다.
문장을 일반화하면,
"웹 브라우저와 웹 서버 사이 HTTP Cache에 재활용하려는 HTTP Resource 결과를 저장한다"
로 요약할 수 있다.
Private, Public? 간단하게만 짚고 가보자.
HTTP Cache 데이터를 캐시하는 곳은 크게 두 곳으로 나뉜다. -> Shared, Public
그리고, 두 가지 타입으로 나뉜다. -> Public, Private
Public은 Private(웹 브라우저)와 Shared(프록시)에 저장한다.
Private는 Private(웹 브라우저)에만 저장한다.
HTTP Cache의 종류에 대해 알아보자. 종류에 대해 알기 앞서, "캐시 데이터를 누가 필요로 하는가? 특정된 한 명인가? 불특정 다수인가?" 에 대한 의문을 가질 수 있다. 이는 Private/Shared로 설명할 수 있다. 그림으로 알아보자.
Cache가 웹 브라우저 안에 있으면 -> 해당 그림의 A.Private를 보면 된다. 이는 해당 웹 브라우저 한 명만을 위한 것이다.
Cache가 웹 브라우저와 서버 사이에 있으면 (Proxy) -> 해당 그림의 B.Shared를 보면 된다. 이는 대다수의 웹 브라우저 유저를 위한 것이다.
정리해보자. '특정 유저 한 명만을 위한 캐시 데이터' -> Web Browser의 Private하게 저장된다.
'불특정 다수를 위한 캐시 데이터' -> Proxy에 Shared 하게 저장된다.
Public, Private, Shared.. 계속해서 이러한 용어가 나오고 있다. HTTP 캐시에서 이 키워드들은 어떤 것을 의미할까?
-> 캐시된 데이터의 접근성과 관련된 속성을 의미한다. 캐시된 내용이 어떻게 공유되거나 접근될 수 있는 지를 나타낸 것
Public 캐시는 여러 사용자에게 공유될 수 있는 데이터를 저장한다. 일반적으로 웹 서버가 모든 사용자에게 동일하게 제공되는 데이터를 캐시할 때 사용된다. 예를 들어, 뉴스 웹사이트의 로고 이미지나, CSS 파일은 변동성이 적고 모든 사용자에게 동일하게 제공되므로 Public 캐시에 저장될 수 있다. Public 캐시는 서버 측 캐시나 공용 프록시 서버에 저장될 수 있다. -> 다수의 사용자에게 동일한 데이터를 제공할 목적이 있기 때문
Private 캐시는 특정 사용자에게만 속한 데이터를 저장하고, 이 데이터는 해당 사용자 외의 다른 사람에게는 제공되지 않는다. 예를 들어, 사용자의 로그인 상태나 개인 설정과 같이 사용자 개인에게 특화된 정보가 Private 캐시에 저장된다. 이 캐시는 개인 사용자의 웹 브라우저에 저장된다.
Shared 캐시는 Public 캐시와 비슷하지만, 여러 사용자가 접근할 수 있는 캐시 서버에서 사용되는 데이터를 주로 의미한다. 예를 들어, ISP가 관리하는 프록시 서버는 Shared 캐시를 사용하여 다수의 사용자에게 데이터를 제공할 수 있다. 주로 기업이나 조직 내부, 혹은 ISP가 관리하는 프록시 서버에 위치한다.
글로 보니까 살짝 어지럽다. 표로써 한 번 정리해보자.
Public | Private | Shared | |
대상 | 웹 서버의 모든 사용자 | 특정 사용자 | 여러 사용자 |
저장 위치 | 서버 측 캐시 / 공용 프록시 | 웹 브라우저 | 기업 및 ISP의 프록시 서버 |
지금까지 HTTP Cache의 의의와 종류에 대해서 다뤄보았다. 이제 HTTP Cache의 동작을 살펴볼 차례이다.
개발자가 HTTP Cache를 사용하기로 결정했다면, 그것이 유효한 전략인지 다시 생각해보아야 한다. 이게 무슨말인가 하면, 데이터의 '실시간성'을 한 번 따져보자는 것이다. 캐시는 데이터의 특정 상태를 저장하여 보관한다. 그런데, 실시간성이 매우 중요한 데이터는 성능에 문제가 되더라도 캐시는 사용하지 않는 게 맞다. 은행 어플리케이션, 자율주행 자동차가 캐시 기반으로 작동한다고 생각해보자. 성능에 심각한 하자가 생기거나, 데이터의 신뢰성에 문제가 생길 것이다.
캐시는 임시(반영구적) 저장을 위한 전략이자, 실시간성을 아예 포기하자는 것이 아닌 준 실시간(準實時間, 실시간에 준하다는 뜻)을 보장하는 정책이다. 즉, 캐시해놓은 데이터가 너무 오래된 데이터가 되지 않도록 특정 주기에 따라 재검증을 해주어야한다는 것을 의미한다.
재검증은 캐시한 데이터의 원본 주인인 웹 서버가 설정한 특정 주기에 따라 캐시한 데이터가 오래되었는 지를 검증하는 것을 말한다.
캐시 재검증에는 주기와 기준이 존재한다. 주기는, 말 그대로 캐시해놓은 데이터를 어떤 간격으로 재검증할지 특정 주기를 의미하는 것이며, 기준은 캐시해놓은 데이터가 오래됐는지 여부를 원본 주인인 웹 서버가 판단하기 위한 근거이다.
먼저 주기부터 보자. 개발자들은 데이터의 갱신 특성에 따라 주기를 설정한다. 자주 바뀌는 데이터, 혹은 잘 바뀌지 않는 데이터에 따라서 그 주기가 달라질 것이다. 주기는 너무 길어도 안 되고, 너무 짧아도 안 된다.
기준은, 캐시해놓은 데이터가 오래됐는지 여부를 원본 주인인 웹 서버가 판단하기 위한 근거라고 하였다. 이 근거에는 수정일(Last-Modified)과 고유값(ETag)가 존재한다.
재검증 기준의 Last-Modified은 말 그대로 수정일(시간)을 기반으로 한다. 웹 서버가 이 헤더를 주었다면 Request Resource의 마지막 수정일, 즉 캐시가 유효한지 여부를 시간을 기반으로 판단한다. 검사 방법으로는 If-Modified-Since와 If-Unmodified-Since가 존재한다.
If-Modified-Since로 요청이 들어오면,
바뀌었으면 -> 서버는 HTTP 상태 코드 200(OK)과, Resource Cache를 반환한다.
바뀌지 않았으면 -> 서버는 HTTP 상태 코드 304 (Not Modified)를 반환한다.
If-Unmodified-Since로 요청이 들어오면,
바뀌었으면 -> 서버는 HTTP 상태 코드 304(Not Modified)를 반환한다.
바뀌지 않았으면 -> 서버는 HTTP 상태 코드 412 (Precondition Failed)를 반환한다.
재검증 기준의 또다른 기준으로 ETag(고유값)이 존재한다. ETag는 해시나 ID를 기반으로 한다. 웹 서버가 Etag 헤더를 주었다면, 전송 Resource의 고유값(해시, ID)을 기반으로 캐시가 유효한지 판단한다. ETag는 If-None-Match와 If-Match 두 가지를 바탕으로 검사한다.
If-None-Match로 요청이 들어오면,
바뀌었으면 -> 서버는 HTTP 상태 코드 200(OK)과, Resource Cache를 반환한다.
바뀌지 않았으면 -> 서버는 HTTP 상태 코드 304 (Not Modified)를 반환한다.
If-Match로 요청이 들어오면,
바뀌었으면 -> 서버는 HTTP 상태 코드 304(Not Modified)를 반환한다.
바뀌지 않았으면 -> 서버는 HTTP 상태 코드 412 (Precondition Failed)를 반환한다.
표로써 한 번 더 정리해보자.
Last-Modified | ETag | |
정확도 및 특징 | 낮은 정확도 - 파일이 수정되지 않았는데 수정일이 변경되는 경우 - 텍스트 파일 수정 후, 다시 원상복구한 경우 수정일만 변경한다. |
높은 정확도 - Last-Modified보다 ETag 사용이 좋은 이유기도 함 - HTTP 1.0, 1.1 호환성을 위해 둘 다 사용하는 편임 |
검사 방법 | - If-Modified-Since : 바뀌었나? - If-Unmodified-Since : 안 바뀌었나? |
- If-None-Match : 바뀌었나? - If-Match : 안 바뀌었나? |
HTTP Cache는 Cache-control 헤더를 통해 세부 설정이 가능하다. 이 설정을 통해 캐시 저장 여부, 캐시 저장 장소, 캐시 재검증 주기, 재검증 강제 등 다양한 옵션을 설정할 수 있다. 캐시할 데이터는 웹 서버가 반환하는 값이고, 반환값에 대한 소유주는 웹 서버이기에, 웹 서버가 캐시를 모두 제어한다.
갑 : 웹 서버이며, 웹 서버가 캐시를 하냐마냐 등을 모두 제어한다. 을 : 해당 반환값을 캐싱하는 웹 브라우저나 프록시에 해당한다.
캐시 저장여부는 no-store, no-cache로 설정할 수 있다. no-store는 캐시를 하지 않음을 의미하며, no-cache는 캐시를 하며 매번 재검증 후 사용한다는 것을 의미한다. no-cache라고 캐싱을 하지 않는 것이 아니니, 혼동하면 안 된다.
캐시 저장장소는 public과 private로 설정할 수 있다. public는 웹 브라우저와 프록시 모두에 저장하게 되며, private는 웹 브라우저에만 저장한다.
캐시 재검증 주기는 max-age와 s-maxage로 설정할 수 있다. max-age는 Expires(유효시간)으로 변환하며, 기존 Expires가 있으면 덮어쓴다. s-maxage는 프록시 캐시에만 적용되는 유효기간이다.
캐시 재검증 강제는 재검증이 꼭 웹 서버와 직접 재검증이 완료된 뒤 캐시를 사용해야한다는 의미의 정책이다. 이는 must-revalidate로 지정한다. 서버와의 접속 문제로 재검증이 실패한 경우 기본 행동은 기존 캐시되어있는 데이터를 반환하는 것이지만, must-revalidate가 활성화되어 있으면 504 에러를 발생시킨다.
'공부 > Web' 카테고리의 다른 글
HTTPS (0) | 2024.04.30 |
---|---|
HTTP의 특성과 Cookie, 간략히 (0) | 2024.04.30 |
Proxy (0) | 2024.04.30 |
CORS(Cross-Origin Resource Sharing)와 동작 시나리오 (0) | 2024.04.28 |
Load Balancer와 Auto Scaling (1) | 2024.04.26 |