HTTP 완벽 가이드 4장

4장 커넥션 관리

1. TCP 커넥션

HTTP 통신은 TCP/IP를 통해 이루어진다.

TCP

Transmission Control Protocol, 전송 제어 프로토콜

  • TCP 커넥션은 인터넷을 안정적으로 연결해준다.
  • TCP는 충돌 없이 순서에 맞게 HTTP 데이터를 전달한다.
  • TCP는 IP 패킷이라 불리는 작은 조각을 통해 데이터를 전송한다.

TCP 커넥션 유지

컴퓨터는 항상 여러 개의 TCP 커넥션을 가지고 있으며, TCP는 포트 번호를 통해서 여러 개의 커넥션을 유지한다.

  • TCP 커넥션은 네 가지 값으로 식별한다.

    <발신지 IP 주소, 발신지 포트, 수신지 IP 주소, 수신지 포트>

2. TCP 성능에 대한 고려

HTTP 트랜잭션 성능은 그 아래 계층인 TCP 성능에 영향을 받는다.

HTTP 트랜잭션 지연

HTTP 트랜잭션을 지연시키는 원인은 여러 가지가 있다.

  • 클라이언트가 해당 호스트에 방문한 적이 없을 경우, 호스트 명을 IP 주소로 변환하는데 시간이 필요하다.
  • 클라이언트가 서버에 TCP 커넥션 요청을 보내고 서버가 커넥션 허용 응답을 회신하길 기다린다.
  • 요청 메시지가 인터넷을 통해 전달되고 서버에 의해 처리되기까지 시간이 소요된다.
  • 웹 서버가 HTTP 응답을 보내는 것 역시 시간이 소요된다.

TCP 커넥션 핸드셰이크 지연

TCP 소프트웨어는 커넥션을 맺기 위한 조건을 맞추기 위해 연속으로 IP 패킷을 교환한다.

작은 크기의 데이터 전송에 커넥션이 사용된다면 이런 패킷 교환은 HTTP 성능을 저하시킬 수 있다.

확인응답 지연

TCP는 성공적인 데이터 전송을 보장하기 위해 자체적인 확인체계를 가진다.
데이를 온전하게 받는데 성공하면 확인응답 패킷을 송신자에게 반환한다.

확인응답은 크기가 작기 때문에 TCP는 같은 방향으로 송출되는 데이터 패킷에 확인응답을 편승시킨다.
만약 같은 방향으로 송출되는 데이터 패킷을 찾지 못하면 지연이 발생한다.

TCP 느린 시작 (slow start)

TCP의 데이터 전송 속도는 TCP 커넥션이 만들어진 지 얼마나 지났는지에 따라 달라진다.
첫 생성시에는 커넥션의 최대 속도를 제한하고 데이터가 성공적으로 전송됨에 따라서 커넥션 속도가 빨라진다.

그렇기 때문에 HTTP에는 이미 존재하는 커넥션을 재사용하는 기능이 있다. (= 지속 커넥션)

네이글(Nagle) 알고리즘과 TCP_NODELAY

세그먼트가 최대 크기가 되기 전까지 전송을 하지 않는다.
다만, 모든 패킷이 확인응답을 받았을 경우에는 최대 크기보다 작은 패킷의 전송을 허락한다.

네이글 알고리즘은 크기가 작은 HTTP 메시지는 패킷을 채우지 못하기 때문에 지연된다는 성능 문제가 존재한다.
성능 향상을 위해 HTTP 스택에 TCP_NODELAY 파라미터 값을 설정하여 네이글 알고리즘 비활성화할 수 있다.

3. HTTP 커넥션 관리

Connection 헤더

HTTP는 클라이언트와 서버 사이에 프락시 서버, 캐시 서버 등과 같은 중개 서버가 놓이는 것을 허락한다.
HTTP Connection 헤더 필드는 커넥션 토큰을 쉼표로 구분하고, 그 값들은 다른 커넥션에 전달되지 않는다.

Connection: close
메시지를 보낸 다음 끊어져야 할 커넥션을 의미

순차적인 트랜잭션 처리에 의한 지연

한 페이지에 여러 트랜잭션이 필요하고, 각 트랜잭션이 새로운 커넥션을 필요로 한다면, 커넥션을 맺는데 발생하는 지연과 함꼐 느린 시작 지연이 발생할 것이다.
또한, 순차적으로 로드하는 방식은 모든 객체를 내려받기 전까지 텅 빈화면을 보여주게 된다.
이를 해결하기 위한 여러 기술이 있다.

  • 병렬(parallel) 커넥션
  • 지속(persistent) 커넥션
  • 파이프라인(pipelined) 커넥션

4. 병렬 커넥션

  • HTTP는 클라이언트가 여러 개의 커넥션을 맺음으로써 여러 개의 HTTP 트랜잭션을 병렬로 처리할 수 있게 한다.
  • 화면에 여러 개의 객체가 동시에 보이면서 내려받고 있는 상황을 볼 수 있기 때문에 사용자는 더 빠르게 내려받는 것처럼 느낄 수 있다.

병렬 커넥션은 페이지를 더 빠르게 내려받는다

각 커넥션의 지연 시간을 겹치게 하여 총 지연 시간을 줄인다.

병렬 커넥션이 항상 더 빠르지는 않다

다수의 커넥션은 메모리 소모가 많고 자체적인 성능 문제를 발생시킬 수 있다.
브라우저는 적은 수(6~8개)의 병렬 커넥션만을 허용한다.
과도한 수의 커넥션이 맺어졌을 경우, 서버는 임의로 커넥션을 끊어버릴 수 있다.

5. 지속 커넥션

  • 처리가 완료된 후에도 계속 연결된 상태로 있는 TCP 커넥션을 지속 커넥션이라 한다.
  • 해당 서버에 이미 맺어져 있는 지속 커넥션을 재사용함으로써, 커넥션을 맺기 위한 준비작업에 따르는 시간을 절약할 수 있다.
  • TCP 느린 시작으로 인한 지연을 피함으로써 더 빠르게 데이터 전송 가능.

HTTP/1.0+의 Keep-Alive 커넥션

  • 커넥션을 유지하기 위해 요청에 Connection:Keep-Alive 헤더를 포함시켜 사용한다.
  • Connection:Keep-Alive 헤더가 없으면, 응답 메시지가 전송되고 나면 커넥션을 끊을 것이라 추정한다.
  • Keep-Alive 헤더 사용은 선택 사항이다.
  • Timeout, max 등의 파라미터를 함께 사용할 수 있다.

    서버가 약 5개의 추가 트랜잭션이 처리될 동안 커넥션을 유지하거나, 2분 동안 커넥션을 유지하라는 내용의 Keep-Alive 응답 헤더 예시.

    Connection: Keep-Alive
    Keep-Alive: max=5, timeout=120

  • HTTP/1.1 명세에서는 keep-alive를 사용하지 않기로 하여 빠져있다.

HTTP/1.1의 ‘지속 커넥션’

  • HTTP/1.1에서는 Keep-Alive 커넥션을 지원하지 않는 대신, 설계가 더 개선된 지속 커넥션을 지원한다.
  • HTTP/1.0의 Keep-Alive 커넥션과 달리 HTTP/1.1의 지속 커넥션은 기본으로 활성화되어있다.
    • 별도 설정을 하지 않는 한, 모든 커넥션을 지속 커넥션으로 취급한다.
  • 커넥션을 끊으려면 Connection: close 헤더를 명시해야 한다.

6. 파이프라인 커넥션

HTTP/1.1은 지속 커넥션을 통해서 요청을 파이프라이닝 할 수 있다.

파이프라인에는 여러 제약 사항이 있다.

  • 지속 커넥션인지 확인하기 전까지는 파이프라인을 이어서는 안된다.
  • HTTP 응답은 요청 순서와 같게 와야 한다.
  • 완료되지 않은 요청이 있다면 언제든 다시 요청을 보낼 준비가 되어있어야 한다.
  • 멱등성이 보장되지 않을 경우 파이프라인을 통해 요청을 보내면 안된다.

7. 커넥션 끊기

커넥션 관리(특히 언제 어떻게 커넥션을 끊는가)에 관한 명확한 기준이 없다.

전체 끊기와 절반 끊기

  • 전체 끊기: close()
  • 절반 끊기: shoutdown()