Atobaum

HTTP 완벽 가이드 정리

1장

HTTP는 단순한 문자열. 요청, 헤더, 본문으로 이루어짐.

HTTP는 tcp로 전달됨(3은 udp쓴다던데...) tcp는

  • 오류 없는 데이터 전송
  • 순서에 맞는 전달
  • 조각 나지 않는 데이터 스트림 을 제공한다.

telnet으로 HTTP 요청을 해보자

$ telnet www.google.com 80
GET / HTTP/1.1
HOST: www.google.com

웹 애플리케이션 중 특이한 사람들:

  • 프락시
  • 캐시
  • 게이트웨이
  • 터널
  • 에이전트 자세한건 후술.

2장 URL과 리소스

헤더는 CRLF로 줄바꿈. body가 없어도 빈줄(CRLF)로 끝나야한다.

4장 커넥션 관리

  • HTTP는 TCP/IP를 이용.
  • HTTP 트랜잭션의 성능은 그 아래 계층인 TCP 성능에 영향르 받는다.

TCP 성능

  • HTTP 트랜잭션을 처리하는 시간보다 TCP 연결 설정, 요청, 응답메시지 전송이 더 오래걸린다.
  • TCP는 비싸다. 대부분의 HTTP 지연은 TCP 지연때문에 발생
  1. TCP 연결 핸드셰이크 지연
  2. 확인 응답 지연: tcp 패킷의 확인 응답은 크기가 작아서 같은 곳으로 송출되는 패킷에 편승 시키는데 요청과 응답으로만 이루어지는 http 동작 방식은 기회를 감소시킨다.
  3. TCP slow start: tcp 연결이 만들어 진 후 시간이 지나면서 최대 속도제한이 늘어난다. 다른말로 초반에는 느리다.
  4. 네이글 알고리즘: 크기가 작은 테이터는 한데 모아서 보낸다.

HTTP 커넥션 관리

어떻게 하면 HTTP 커넥션 성능을 향상시킬 수 있을 까?

Parallel connection

여러 커넥션으로 한꺼번에 처리. 그러나 대역폭이 충분하지 않으면 효과가 없고 오히려 관리비용때문에 느려질 수도 있다. 브라우저는보총 적은 수(6-8개)의 커넥션을 사용한다.

Persistent connection

한 페이지에 있는 링크들은 대부분 같은 서버에 있다. TCP 연결을 일회용으로 쓰지 않고 재사용. TCP 연결 지연 시간을 줄일 수 있다. 게다가 tcp의 느린 시작으로 인한 지연도 줄일 수 있다.

keep-alive 헤더는 HTTP/1.1에서는 빠졌다. 그러나 아직 사용되고 있다. (HTTP/1.1에서는 지속 커넥션이 기본). 그러나 연결을 보장하지는 않는다. 누군가 언제든지 연결을 끊을 수 있음.

중간에 프록시 서버가 있으면 문제가 생길 수 있다. 만약 프록시가 헤더를 살펴보지 않고 그냥 전달만 한다면 클라이언트와 서버는 각각 프록시와 연결이 지속될거라고 기대하는데 프록시는 양쪽과 연결을 끊어버린다. 이를 피하기 위해 중계 서버를 통해 이뤄질 경우 클라이언트는 Proxy-Connection 헤더를 사용하기도 한다. 만약 프록시가 멍청하다면 서버는 Connection 헤더가 없어서 연결을 끊고 프록시가 똑똑하면 Proxy-Connection을 Connection으로 바꿔보내고 연결을 유지한다.

HTTP/1.1에서는 별도 설정을 하지 않는 한 모든 커넥션을 지속 커넥션으로 간주. HTTP/1.1 어플리케이션은 Connection: close를 명시해야한다.

Pipelined connection

한 커넥션에서 응답이 도착하기 전에 요청을 보내기.

  • 지속 커넥션에서만 이용해야한다.
  • HTTP 메시지는 순번이 정해져있지 않아 요청 순서과 똑같이 응답이 와야한다.
  • HTTP 클라이언트는 커넥션이 언제 끊어지더라도 완료되지 않은 요청이 있으면 요청을 다시 보낼 준비가 되어있어야. 서버가 반만 보내고 연결 끊을 수도.
  • POST와 같이 반복해서 보낼 경우 문제가 생기는 요청은 보내면 안된다.

어떻게 커넥션을 끊을까

  • 마음대로 끊기 주의: 몇번 실행됬는지에 상관 없이 결과가 같다면 멱등(idempotent)하다고 한다. GET, HEAD, PUT, DELETE 같은거. 그런데 POST 같이 멱등이 아닌 요청은 파이프라인을 통해 보내면 안된다.

  • 우아하게 끊기 먼저 반만(출력체널)만 끊고 입력이 끊어지기를 기다릴 수도 있다.

7장 캐시

캐시는 무엇을 해결할까:

  • 불필요한 데이터 전송
  • 대역폭 병목
  • 갑작스런 요청 쇄도
  • 거리로 인한 지연

캐시는 무슨 문제가 있을까:

  • 캐시가 최신 정보인지 확인이 필요

문제를 어떻게 해결할까:

  • 재검사(revalidation): 여러가지 방법이 있다. 예를들어 서버에 요청을 보내지만 If-Modified-Since 헤더를 이용. 안바뀌었으면 304 Not Modified 응답을 보낸다.

캐시 토폴로지

  • 개인 전용 캐시: 예를 들어 브라우저 내장 캐시
  • 공용 프락시 캐시
  • 프락시 캐시에도 계층이 있을 수 있다.

캐시 처리 단계

  1. 요청 받기
  2. 파싱: 캐시가 요청에서 URL과 헤더들을 추출
  3. 검색: 가지고 있는가?
  4. 신선도 검사: 가지고 있으면 신선한지 (잘) 검사
  5. 응답 생성
  6. 발송
  7. 로깅

신선한 사본

HTTP는 Cache-Control과 Expires라는 헤더를 이용해 원 서버가 리소스에 유휴기간을 붙일 수 있도록 해준다.

Cache-Control: max-age=484200
Expires: Fri, 05 Jul 2002, 05:00:00 GMT

Cache-Control: max-age는 남은 시간을 초로 지정. Expires는 유효기간은 GMT로 지정 만약 캐시 서버의 시간이 동기화되있지 않으면 Expires는 잘 작동을 안 할 수도 있다.

또는 ETag 사용: 주석 추가 같은 다르지만 같은 리소스나 최근 변경 일시를 정확하게 판별할 수 없거나 1초의 정밀도가 충분하지 않을 떄.

캐시제어

  • Cache-Control: no-store: 리소스의 사본을 만드는 것을 금지. 개인정보가 들어있거나.
  • Cache-Control: no-cache: 로컬 캐시 저장소에 저장될 수 있음. 다만 서버와 재검사 필수.
  • Cache-Control: must-revalidate: 캐시는 성능 개선을 위해 만료된 객체를 제공할 수 있다. 이 헤더를 설정하면 ㅇ만료된 객체를 재검사 없이 재공해서는 안된다.

서버가 알려주지 않을 때

캐시 서버는 알아서 추측한다. 예를들어

  • 마지막 변경일이 오래됬다면 안정적인 문서로 예측, vice versa.

클라이언트 신손도 제약

  • Cache-Control: max-stale: 신선하지 않아도 된다.
  • Cache-Control: min-fresh = <s>: 만료기간이 s초 이상 남아야 한다.
  • 등등