HTTP 완벽 가이드 2부 - HTTP 아키텍처(2/2)

Updated:

HTTP 완벽 가이드 시리즈를 정리한 내용입니다.

7장 캐시

7.1 불필요한 데이터 전송

  • 여러 클라이언트들이 자주 쓰이는 원 서버 페이지에 접근한다면, 원 서버는 클라이언트들에게 같은 응답을 각각 한번씩 전송한다.
  • 이러한 불필요한 전송은 값비싼 네트워크 대역폭을 잡아먹고, 전송을 느리게 만들고, 웹 서버에 부하를 준다.
  • 캐시를 이용하자

7.2 대역폭 병목

  • 네트워크는 원격서버보다 로컬 네트워크 클라이언트에서 더 넓은 대역폭을 제공한다.
  • 클라이언트가 LAN에 있는 캐시로부터 사본을 가져온다면 성능을 대폭 개선할 수 있다.

7.3 갑작스런 요청 쇄도

  • 갑작스런 사건이 있따면 같은 웹 문서에 대해 많은 요청이 들어온다.
  • 이러한 불필요한 트래픽 급증은 네트워크와 웹 서버의 심각한 장애를 야기한다.

7.4 거리로 인한 지연

  • 대역폭이 문제가 되지 않더라도 거리가 문제가 될 수 있다.
  • 빛의 속도의 한계로, 결국 전송되어야 하는 거리가 멀면 시간이 오래걸린다.

7.5 적중과 부적중

  • 캐시가 세상 모든 문서의 사본을 저장하지는 않는다.
  • 캐시 적중: 요청이 도착했을 때 해당하는 사본이 있다.
  • 캐시 부적중: 해당하는 사본이 없어 원 서버로 요청이 전달된다.

7.5.1 재검사

  • 원 서버의 콘텐츠는 변경될 수 있으므로 캐시는 갖고있는 사본이 최신인지 때때로 점검해야 한다. -> 신선도 검사
  • 캐시는 스스로 사본을 재검사할 수 있지만, 대체로 클라이언트가 사본을 요청하고 그 사본이 검사를 필요로 할 정도로 오래됐을 때 재검사한다.
  • 캐시가 재검사 요청을 원 서버로 보냈을 때, 콘텐츠가 변경되지 않았다면 304 Not Modified응답을 보낸다.
    • 캐시는 사본이 신선하다고 다시 표시한 뒤 사본을 클라이언트에게 제공한다.
    • 재검사 적중, 느린 적중이라 부른다.
  • 캐시 적중보다는 느리고 캐시 부적중보다는 빠르다.
  • If-Modified-Since헤더가 가장 많이 사용된다.

재검사 적중

  • 서버는 클라이언트에게 작은 304 Not Modified 응답을 보낸다.

재검사 부적중

  • 서버 객체가 캐시된 사본과 다르면, 서버는 콘텐츠 전체와 함께 200 OK 응답을 보낸다.

객체 삭제

  • 서버 객체가 삭제되었다면, 서버는 404 Not Found 응답을 보내며 캐시는 사본을 삭제한다.

7.5.2 적중률

  • 캐시가 요청을 처리하는 비율을 캐시 적중률, 문서 적중률 이라고 부른다.
  • 0에서 1의 값으로 되어있으나, 흔히 퍼센트로 표현하기도 한다. (100%면 모두 적중)
  • 문서 적중률을 개선하면 전체 대기시간(지연)이 줄어든다.

7.5.3 바이트 적중률

  • 문서들이 항상 같은 크기인 것은 아니다.
  • 큰 객체는 덜 접근되지만, 캐시가 적중하면 트래픽에 더 크게 기여한다.
  • 바이트 적중률을 개선하면 대역폭 절약을 최적화한다.

7.5.4 적중과 부적중의 구별

  • HTTP는 클라이언트에게 응답이 캐시 적중이었는지, 원서버의 접근인지 말해줄 수 있는 방법이 없다.
  • Date헤더는 응답이 생성됐을때의 시각을 표시하므로, 이를 현재 시각과 비교하면 캐시된 응답인지 알아낼 수 있다.

7.6 캐시 토폴로지

  • 캐시는 한 명에게만 할당된 개인 전용 캐시와 공유된 캐시인 공용 캐시로 나눌 수 있다.

7.6.1 개인 전용 캐시

  • 웹 브라우저는 개인 전용 캐시를 내장한다.
  • 자주 쓰이는 문서를 디스크와 메모리에 캐시한다.

7.6.2 공용 프록시 캐시

  • 프록시 캐시는 로컬 캐시에서 문서를 제공하거나, 사용자 입장에서 서버에 접근한다.
  • 여러 사용자가 접근하므로, 불필요한 트래픽을 더 많이 줄일 수 있다.

7.6.3 프록시 캐시 계층들

  • 작은 캐시에서 캐시 부적중이 발생하면, 더 큰 부모 캐시가 걸러진 트래픽을 처리하도록 하는 것이 합리적이다.
  • 클라이언트에 가까울수록 작고 저렴한 캐시를 사용하고, 많은 사용자들에게 공유되는 문서는 계층 상단에 위치한다.

7.6.4 캐시망, 콘텐츠 라우팅, 피어링

  • 몇몇 네트워크 아키텍처는 단순한 캐시 계층 대신 복잡한 캐시망을 만든다.
  • 어떤 부모 캐시와 대화할 것인지, 아니면 바로 원 서버로 요청이 가도록 할 것인지 동적으로 결정한다.
  • 서로 다른 조직들이 상호 이득을 위해 그들의 캐시를 연결하여 서로를 찾아볼 수 있도록 해주기도 한다.

7.7 캐시 처리 단계

7.7.1 단계 1: 요청 받기

  • 캐시가 네트워크 커넥션에서의 활동을 감지하고, 들어오는 데이터를 읽는다.

7.7.2 단계 2: 파싱

  • 요청 메세지를 여러 부분으로 파싱하여 헤더 부분을 조작하기 쉬운 자료구조에 담는다.
  • 캐싱 소프트웨어가 헤더 필드를 처리하고 조작하기 쉽게 만든다.

7.7.3 단계 3: 검색

  • 캐시는 URL을 알아니내고 해당하는 로컬 사본이 잇는지 검사한다.
  • 로컬에서 가져올 수 없다면, 원서버, 부모 프록시에서 가져오거나, 혹은 실패를 반환한다.

7.7.4 단계 4: 신선도 검사

  • 캐시된 사본이 신선도 한계를 넘을 정도로 오래되었다면, 신선하지 않은 것으로 간주되어 서버와 재검사를 해야한다.

7.7.5 단계 5: 응답 생성

  • 캐시된 서버 응답 헤더를 토대로 응답 헤더를 생성한다.
  • 캐시는 클라이언트의 상황에 맞추어 헤더를 적절하게 번역해야 한다.
  • 캐시 또한 캐시 신선도 정보를 삽입해야 한다.
  • Date 헤더는 객체가 원 서버에서 최초로 생겨난 일시를 표현하는 것이므로 캐시가 조정해서는 안된다.

7.7.6 단계 6: 전송

  • 캐시는 응답을 클라이언트에게 돌려준다.

7.7.7 단계 7: 로깅

  • 대부분의 캐시는 로그 파일과 캐시 사용에 대한 통계를 유지한다.
  • 각 캐시 트랜잭션이 완료된 후, 통계 캐시 적중과 부적중 횟수에 대한 통계를 갱신하고 로그 파일에 요청 종류, URL 그리고 무엇이 일어났는지를 알려주는 항목을 추가한다.

7.8 사본을 신선하게 유지하기

7.8.1 문서 만료

  • Cache-ControlExpires라는 헤더를 이용해서 원 서버가 각 문서에 유효기간을 붙일 수 있다.

7.8.2 유효기간과 나이

  • Cache-Control: max-age: 문서의 최대 나이를 정의한다. 문서의 신선도 유효기간을 초단위로 지정한다.
  • Expires: 절대 유효기간을 명시한다.

7.8.3 서버 재검사

  • 재검사 결과 콘텐츠가 변경되었다면, 캐시는 그 문서의 새로운 사본을 가져와 오래된 데이터 대신 저장한 뒤 클라이언트에게도 보내준다.
  • 재검사 결과 콘텐츠가 변경되지 않았다면, 캐시는 새 만료일을 포함한 새 헤더들만 가져와서 캐시 안의 헤더들을 갱신한다.
  • 캐시의 응답의 종류
    • 충분히 신선한 캐시된 사본
    • 원 서버와의 재검사를 마치고 신선하다고 확신할 수 있는 사본
    • 에러 메세지(원 서버 다운등으로 인한 재검사 불가능)
    • 경고 메세지가 부착된 캐시된 사본(부정확할 수 있음)

7.8.4 조건부 메서드와의 재검사

  • GET메세지에 특별한 헤더를 추가하여 재검사를 실시한다.
  • If-Modified-Since: 문서가 주어진 날짜 이후로 수정되었다면 요청 메서드를 처리한다.
  • If-None-Match: 문서에 대한 특별한 태그를 비교하여 다르다면 요청 메서드를 처리한다.

7.8.5 If-Modified-Since: 날짜 재검사

  • 문서가 주어진 날짜 이후 변경되었다면, 조건은 참이므로 새문서와 새로운 만료날짜가 담긴 헤더 등이 캐시에게 반환된다.
  • 변경되지 않았다면, 조건은 거짓이므로 304 Not Modified와 갱신이 필요한 것(새로운 만료 날짜 등)을 캐시에게 반환한다.
  • 마지막으로 변경된 일시인 Last-Modified헤더와 함께 동작한다.

7.8.6 If-None-Match: 엔티티 태그 재검사

  • 최근 변경 일시 재검사가 행해지기 어려운 상황이 있다.
    • 일정 간격으로 다시 쓰여지지만 내용에는 변화가 없을 때
    • 문서의 변경이 다시 캐시하기에는 너무나도 사소할 때
    • 서버가 갖고있는 페이지에 대한 최근 변경 일시를 정확하게 판별할 수 없을 때
    • 1초보다 적은 간격으로 갱신되는 문서를 가진 서버여서 1초보다 더 작은 정밀도가 필요할 때
  • 퍼블리셔는 문서를 변경했을 때 문서의 엔티티 태그를 새로운 버전으로 표현한다.

7.8.7 약한 검사기와 강한 검사기

  • HTTP1.1은 서버가 캐시된 사본들을 무효화하지 않고 문서를 조금 고치고 싶을 때 사용할 수 있는 약한 검사기를 지원한다.
  • 강한 검사기는 콘텐츠가 바뀔 때마다 무조건 바뀐다.
  • 서버는 W/접두사로 약한 검사기를 구분한다.

7.8.8 언제 엔티티 태그를 사용하고 언제 Last-Modified 일시를 사용하는가

  • HTTP/1.1 클라이언트는 만약 서버가 엔티티 태그를 반환했다면, 반드시 엔티티 태그 검사기를 사용해야 한다.
  • 서버가 Last-Modifeid 값만을 반환했다면, 클라이언트는 If-Modifed-Since 검사를 사용할 수 있다.
  • 모두 사용 가능하다면, 클라이언트는 두 가지의 재검사 정책을 모두 사용해야 한다.
  • HTTP/1.1 원 서버는 가능하다면 엔티티 태그 검사기를 보내야 한다.
  • 모든 조건에 부합할 때만 304 Not Modifed 응답을 반환해야 한다.

7.9 캐시 제어

  • 문서가 만료되기 전까지 얼마나 오랫동안 캐시될 수 있게 할 것인지 서버가 설정할 수 있다.

7.9.1 no-cache와 no-store 응답 헤더

Cache-Control: no-store
Cache-Control: no-cache
Pragma: no-cache

  • no-store는 캐시가 그 응답의 사본을 만드는 것을 금지한다.
  • no-cache는 캐시가 저장될 수 있으나, 재검사를 하지 않고서는 캐시에서 클라이언트로 제공될 수 없다.
  • Pragma: no-cache는 HTTP/1.0+와의 하위호환성을 위해 포함되어 있다.

7.9.2 Max-Age 응답 헤더

Cache-Control: max-age=3600
Cache-Control: s-maxgage=3600

  • max-age는 신선하다고 간주되었던 문서가 서버로부터 온 이후로 흐른 시간이다.
  • s-maxagemax-age와 같지만 공유된 캐시에서만 적용된다.

7.9.3 Expires 응답 헤더

Expires: Fri, 05 Jul 2002, 05:00:00 GMT

  • 초 단위의 시간 대신 실제 만료 날짜를 명시한다.
  • 많은 서버가 동기화되어있지 않기 때문에, max-age가 더 유용하다.
  • 0으로 설정할 수 있으나, 이는 문법 위반이고 사용해서는 안된다.

7.9.4 Must-Revalidate 응답 헤더

Cache-Control: must-revalidate

  • 캐시가 성능을 위해 만료된 객체를 제공하도록 설정할 수도 있는데, 이를 방지한다.
  • 이 객체의 신선하지 않은 사본을 원 서버와의 최초의 재검사 없이는 재사용해서는 안 됨을 의미한다.
  • 원 서버가 사용할 수 없는 상태라면, 반드시 504 Gateway Timeout error를 반환해야 한다.

7.9.5 휴리스틱 만료

  • 응답이 Cache-Control: max-age헤더나 Expires헤더 모두 포함하지 않으면 캐시는 경험적인 방법으로 최대 나이를 계산한다.
  • 유명한 휴리스틱 만료 알고리즘으론 LM 인자 알고리즘이 있으며, 문서가 최근 변경 일시를 포함하고 있다면 사용할 수 있다.
    • 캐시된 문서가 마지막으로 변경된 것이 상당히 오래전이라면, 안정적인 문서이고 변경가능성이 크지 않을 것이라고 판단하여 더 오래 보관한다.
    • 캐시된 문서가 최근에 변경됐다면, 자주 변경될 것이라고 생가갛여 짧은 기간만 보관한다.
  • 최근 변경일 조차 없다면 근거가 없으므로 기본 신선도 유지기간을 설정한다.

7.9.6 클라이언트 신선도 제약

  • 클라이언트는 Cache-Control 요청 헤더를 사용하여 만료 제약을 엄격하게 하거나 느슨하게 할 수 있다.

Tags:

Categories:

Updated:

Leave a comment