Study

[HTTP 완벽 가이드] 4장 : 커넥션 관리

이웃비 2020. 12. 16. 22:16

 

전 세계 모든 HTTP통신은, 지구 상의 컴퓨터와 네트워크 장비에서 널리 쓰이고 있는 패킷 교환 네트워크 프로토콜들의 계층화된 집합인 TCP/IP를 통해 이루어진다

 


1. TCP 커넥션

 

 

1.1 신뢰할 수 있는 데이터 전송 통로인 TCP

  • TCP 커넥션은 인터넷을 안정적으로 연결해준다. TCP는 충돌 없이 순서에 맞게 HTTP데이터를 전달한다

  • 웹브라우저가 TCP커넥션을 통해서 웹 서버에 요청을 보낸다

    1. 브라우저가 www.joes-hardware.com라는 호스트명을 추출한다

    2. 브라우저가 이 호스트 명에 대한 IP주소를 찾는다

    3. 브라우저가 포트 번호(80)를 얻는다

    4. 브라우저가 202.43.78.3의 80 포트로 TCP 커넥션을 생성한다

    5. 브라우저가 서버로 HTTP GET 요청 메시지를 보낸다

    6. 브라우저가 서버에서 온 HTTP응답 메시지를 읽는다

    7. 브라우저가 커넥션을 끊는다

 

1.2 TCP 스트림은 세그먼트로 나뉘어 IP 패킷을 통해 전송된다

  • HTTP가 메시지를 전송하고자 할 경우, 현재 연결되어 있는 TCP 커넥션을 통해서 메시지 데이터의 내용을 순서대로 보낸다. TCP는 세그먼트라는 단위로 데이터 스트림을 잘게 나누고, 세그먼트를 IP 패킷이라고 불리는 봉투에 담아서 인터넷을 통해 데이터를 전달한다. 이 모든 것은 TCP/IP 소프트웨어에 의해 처리된다.

1.3 TCP 커넥션 유지하기

  • 회사의 대표 전화번호는 안내 데스크로 연결되고 내선전화는 해당 직원으로 연결되듯이 IP주소는 해당 컴퓨터에 연결되고 포트번호는 해당 애플리케이션으로 연결된다.

  • TCP 커넥션의 식별 : <발신지IP주소, 발신지포트, 수신지 IP주소, 수신지 포트>

1.4 TCP소켓 프로그래밍

2. TCP의 성능에 대한 고려

2.1 HTTP 트랜잭션 지연

  • HTTP 트랜잭션을 지연시키는 원인

  1. URL에 기술되어 있는 호스트에 방문한 적이 최근에 없으면 DNS 이름 분석 인프라를 사용하여 URL에 있는 호스트명을 IP주소로 변환하는 데 수십 초의 시간이 걸릴 것이다

  2. 클라이언트는 TCP커넥션 요청을 서버에게 보내고 서버가 커넥션 허가 응답을 회신하기를 기다리는데, 수백개의 HTTP트랜잭션이 만들어지면 소요 시간은 증가할 것이다

  3. 커넥션 후 HTTTP요청을 전송하고 요청 메시지를 서버에 의해 처리하는 데 시간이 소요된다

  4. 웹 서버가 HTTP응답을 보내는것 역시 시간이 소요된다

2.2 성능 관련 중요 요소

2.3 TCP 커넥션 핸드셰이크 지연

  • TCP 커넥션 핸드셰이크 지연의 경우

  • 결국 크기가 작은 HTTP트랜잭션은 50% 이상의 시간을 TCP를 구성하는데 쓴다.

2.4 확인응답 지연

  • 각 TCP세그먼트는 순번과 데이터 무결성 체크섬을 가진다. 각 세그먼트의 수신자는 세그먼트를 온전히 받으면 작은 확인응답 패킷을 송신자에게 반환한다.

  • 확인응답은 그 크기가 작기 때문에, TCP는 같은 방향으로 송출되는 데이터 패킷에 확인응답을 편승시킨다.

  • 많은 TCP스택은 '확인응답 지연' 알고리즘을 구현하여, 송출할 확인응답을 특정 시간 동안 버퍼에 저장해 두고, 확인응답을 편승시키기 위한 송출데이터 패킷을 찾는다. 만약 일정 시간 안에 송출 데어터 패킷을 찾지 못하면 확인응답은 별도 패킷을 만들어 전송된다.

  • 만상 편승할 패킷을 찾으려고 하면 해당 방향으로 송출될 패킷이 많지 않기 때문에, 확인응답 지연 알고리즘으로 인한 지연이 자주 발생한다.

2.5 TCP느린 시작(slow start)

  • TCP의 느린 시작은 TCP가 한 번에 전송할 수 있는 패킷의 수를 제한한다. 간단히 말해서, 패킷이 성공적으로 전달되는 각 시점에 송신자는 추가로 2개의 패킷을 더 전송할 수 있는 권한을 얻는다.

  • HTTP트랜잭션에서는 전송할 데이터의 양이 많으면 모든 패킷을 한 번에 전송할 수 없다. 그 대신 한 개의 패키산 전송하고 확인응답을 기다려야 한다. 확인응답을 받으면 2개의 패킷을 보낼 수 있으며, 그 패킷 각각 대한 확인응답을 받으면 총 4개의 패킷을 보낼 수 있게 된다.

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

  • 네이글 알고리즘은 세그먼트가 최대 크기가 되지 않으면 전송을 하지 않는다. 다만 다른 모든 패킷이 확인응답을 받았을 경우에는 최대 크기보다 작은 패킷의 전송을 허락한다. 다른 패킷들이 아직 전송 중이면 데이터는 버퍼에 저장된다. 전송되고 나서 확인응답을 기다리던 패킷이 확인응답을 받았거나 전송하기 충분할 만큼의 패킷이 쌓였을 때 버퍼에 저장되어 있던 데이터가 전송된다

  • 네이글 알고리즘의 문제

  • HTTP스택에 TCP_NODELAY파라미터 값을 설정하여 네이글 알고리즘을 비활성화하기도 한다

2.7 TIME_WAIT 의 누적과 포트 고갈

  • TCP 커넥션의 종단에서 TCP커넥션을 끊으면, 종단에서는 커넥션의 IP주소와 포트 번호를 메모리의 작은 제어영역에 기록해 놓는다. 이 정보는 같은 주소와 포트 번호를 사용하는 새로운TCP커넥션이 일정 시간 동안에는 생성되지 않게 하기 위한 것으로, 보통 세그먼트의 최대 생명주기에 두배 정도의 (2분)시간 동안만 유지된다

  • 이는 이전 커넥션과 관련된 패킷이 그 커넥션과 같은 주소와 포트 번호를 가지는 새로운 커넥션에 삽입되는 문제를 방지한다.

  • 그러나 성능시험을 하는 상황에서는 문제가 될 수 있다. 성능 측정 대상 서버는 클라이언트가 접속할 수 있는 IP주소의 개수를 제한하여 가능한 연결의 조합이 제한되며, TIME_WAIT로 인해서 순간순간 포트를 재활용하는 것이 불가능해진다.

  • 포트 고갈 문제를 격지 않더라도, 커넥션을 너무 많이 맺거나 대기 상태로 있는 제어 블록이 너무 많아지는 상황은 주의해야한다

 

3. HTTP 커넥션 관리

3.1 흔히 잘못 이해하는 Connection 헤더

  • Connection헤더는 전송자가 특정 커넥션에만 해당되는 옵션을 지정하게 해 준다

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

  • 예를들어 3개의 이미지가 있는 웹페이지가 있으면 브라우저는 이 페이지를 보여주기 위해 네 개의 HTTP트랜잭션을 만들어야 하고, 각 트랜잭션이 새로운 커넥션을 필요로 한다면, 커넥션을 맺는데 발생하는 지연과 함께 느린 시작 지연이 발생할 것이다

 

4. 병렬 커넥션

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

  • HTML페이지를 먼저 내려받고 남은 세개의 트랜잭션이 각각 별도의 커넥션에서 동시에 처리되면 이미지들을 병렬로 내려받아 커넥션 지연이 겹쳐짐으로써 총 지연시간이 줄어든다.

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

  • 클라이언트의 네트워크 대역폭이 좁을 때는 대부분의 시간을 데이터를 전송하는 데만 쓸 것이다. 이 제한된 대역폭 내에서 각 객체를 전송받는 것은 느리기 때문에 성능상의 장점은 없어진다. 실제로는, 여러 개의 커넥션을 생성하면서 생기는 부하 때문에, 객체들을 순차적으로 내려받는 것보다 더 오래 걸릴수있다.

4.3 병렬 커넥션은 더 빠르게 '느껴질 수' 있다

  • 그러나 화면에 여러 개의 객체가 보이면서 내려받는 상황을 볼 수 있기 때문에 사용자는 더 빠르게 내려받고 있는 것처럼 느낄 수 있다.

5. 지속 커넥션

  • 웹 페이지에 첨부된 이미지들은 같은 웹 사이트 내에 있고, 웹 페이지 내의 이미지 등을 가져오기 위해서 그 서버에 또 요청하게 될 것이다. 이 속성을 사이트 지역성이라 부른다.

  • 처리가 완료된 후에도 TCP 커넥션을 유지하여 계속 연결된 상태로 있는 것을 지속 커넥션이라고 부른다

  • 해당 서버에 이미 맺어져 있는 지속 커넥션을 재사용함으로써, 커넥션을 맺기 위한 준비작업에 따르는 시간을 절약할 수 있다

5.1 지속 커넥션 vs 병렬 커넥션

  • 지속 커넥션은 잘못 관리할 경우 계속 연결된 상태로 있는 수많은 커넥션이 쌓이게 될 것이다. 지속 커넥션은 병렬 커넥션과 사용될 때 가장 효과적이다

5.2 HTTP/1.0+의 Keep-Alive 커넥션

5.3 Keep-Alive 동작

  • HTTP/1.0 keep-alive커넥션을 구현한 클라이언트는 커넥션을 유지하기 위해서 요청에 Connectioin : Keep-Alive 헤더를 포함시킨다. 서버는 요청을 받고 그다음 요청도 이 커넥션을 통해 받고자 한다면 응답 메시지에 같은 헤더를 포함시켜 응답한다

5.4 Keep-Alive 옵션

  • 클라이언트나 서버가 keep-alive요청을 받았다고 해서 무조건 그것을 따를 필요는 없다

  • 옵션은 Connectioin : Keep-Alive헤더가 있을 때만 사용할 수 있다

    • timeout : 커넥션이 얼마나 유지될 것인지

    • max : 커넥션이 몇 개의 트랜잭션을 처리할 동안 유지할 것인지

5.5 Keep-Alive 커넥션 제한과 규칙

5.6 Keep-Alive와 멍청한(dumb) 프락시

  • 클라이언트가 의도한 Connection헤더는 홉 별(hop-by-hop) 헤더이나, 프락시는 이를 이해하지 못했다.

  • 클라이언트가 응답 메시지를 받은 후 다음 요청을 보내면 프락시는 같은 커넥션상에서 다른 요청이 오는 경우는 예상하지 못하기 때문에 요청을 무시하고, 브라우저는 아무런 응답 없이 로드 중이라는 표시만 띄우다가 타임아웃난다

5.7 Proxy-Connection 살펴보기

5.8 HTTP/1.1의 지속 커넥션

  • HTTP/1.1 클라이언트는 응답에 Connection: close 헤더가 없으면 응답 후에도 커넥션을 계속 유지하자는 것으로 추정한다

5.9 지속 커넥션의 제한과 규칙

 

6. 파이프라인 커넥션

  • HTTP 클라이언트는 커넥션이 지속 커넥션인지 확인하기 전까지는 파이프라인을 이어서는 안 된다

  • HTTP 응답은 요청 순서와 같게 와야 한다

  • HTTP클라이언트는 커넥션이 언제 끊어지더라도, 완료되지 않은 요청이 파이프라인에 있으면 언제든 다시 요청을 보낼 수 있어야 한다

  • HTTP클라이언트는 서버에 데이터에 변화가 생기는 POST 요청같이 반복해서 보낼 경우 문제가 생기는 요청을 파이프라인을 통해 보내면 안 된다. 에러가 발생할 경우 어떤 것들이 서버에서 처리되었는지 알 방법이 없기 때문이다

 

7. 커넥션 끊기에 대한 미스터리

7.1 '마음대로' 커넥션 끊기

7.2 Content-Length와 Truncation

  • 클라이언트나 프락시가 커넥션이 끊어졌다는 응답을 받은 후, 실제 전달된 엔터티의 길이와 Content-Longth의 값이 일치하지 않거나 아예 존재하지 않으면 서버에게 정확한 길이를 물어봐야 한다

7.3 커넥션 끊기의 허용, 재시도, 멱등성

7.4 우아한 커넥션 끊기

  • 일반적으로 애플리케이션이 우아한 커넥션 끊기를 구현하는 것은 애플리케이션 자신의 출력 채널을 먼저 끊고 다른 쪽에 있는 기기의 출력 채널이 끊기는 것을 기다리는 것이다

 

출처 : 데이빗 골리 외 4인, HTTP 완벽 가이드 :웹은 어떻게 동작하는가, 이응준 , 정상일 옮김, 인사이트, 2014