ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [HTTP 완벽 가이드 4장] 커넥션 관리
    Network 2020. 6. 22. 10:17
    반응형

    이 장에서 배울 것

    • HTTP는 어떻게 TCP 커넥션을 사용하는가
    • TCP 커넥션의 지연, 병목, 막힘
    • 병렬 커넥션, keep-alive 커넥션, 커넥션 파이프라인을 활용한 HTTP의 최적화
    • 커넥션 관리를 위해 따라야 할 규칙들

    4.1 TCP 커넥션

    • 전 세계 모든 HTTP 통신은 패킷 교환 네트워크 프로토콜들의 계층화된 집합인 TCP/IP를 통해 이루어진다.
    • 세계 어디에서든 클라이언트와 서버는 TCP/IP 커넥션을 맺을 수 있다.
    • 일단 커넥션이 맺어지면 클라이언트와 서버간에 주고받는 메시지는 안전하게 전달된다.

    패킷 교환(Packet switching)이란?
    컴퓨터 네트워크와 통신의 방식 중 하나로 현재 가장 많은 사람들이 사용하는 통신 방식이다.
    작은 블록의 패킷으로 데이터를 전송하며 데이터를 전송하는 동안만 네트워크 자원을 사용하도록 하는 방법을 말한다.

    URL을 입력받은 브라우저가 수행하는 7단계 과정

    URL : http://www.joes-hardware.com:80/power-tools.html

    1. www.joes-hardware.com이라는 호스트 명을 추출한다.
    2. 이 호스트 명에 대한 IP 주소를 찾는다.
      www.joes-hardware.com -> 202.43.78.3
    3. 포트번호(80)를 얻는다.
    4. 202.43.78.3의 80포트로 TCP 커넥션을 생성한다.
    5. 서버로 HTTP GET 요청 메시지를 보낸다.
    6. 서버에서 온 HTTP 응답 메시지를 읽는다.
    7. 커넥션을 끊는다.

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

    • TCP 커넥션은 인터넷을 안정적으로 연결해준다.
    • TCP 커넥션 한쪽에 있는 바이트들은 반대쪽으로 순서에 맞게 정확히 전달된다.

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

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

    IP 패킷이 포함하는 것

    1. IP 패킷 헤더 (보통 20byte)
      발신자와 목적지 IP 주소, 크기, 기타 플래그
    2. TCP 세그먼트 헤더 (보통 20byte)
      TCP 포트 번호, TCP 제어 플래그, 데이터의 순서와 무결성을 검사하기 위해 사용되는 숫자 값
    3. TCP 데이터 조각 (0 혹은 그 이상의 byte)

    3) TCP 커넥션 유지하기

    • TCP 커넥션은 네 가지 값으로 식별한다.
      <발신지 IP 주소, 발신지 포트, 수신지 IP 주소, 수신지 포트>
    • 이 네 가지 값으로 유일한 커넥션을 생성한다.

    4) TCP 소켓 프로그래밍

    소켓(Socket)이란?

    • 프로그램이 네트워크에서 데이터를 송수신할 수 있도록 "네트워크 환경에 연결할 수 있게 만들어진 연결부"
    • 두 프로그램이 네트워크를 통해 서로 통신을 수행할 수 있도록 양쪽에 생성되는 링크의 단자이다.
    • 두 소켓이 연결되면 서로 다른 프로세스끼리 데이터를 전달할 수 있다.
    • 상대방에게 데이터를 보내거나 받는 역할을 한다.

    TCP/IP 소켓 통신이란?

    • 클라이언트 프로그램과 서버 프로그램은 각각 자신의 포트를 통해 통신을 해야 하는데, 소켓을 통해 연결한다.

    클라이언트 소켓과 서버 소켓

    • 최초 어느 한 곳(클라이언트)에서 그 대상(서버)이 되는 곳으로 연결을 요청한다.
    • IP 주소와 포트 번호로 식별되는 대상에게, 자신이 데이터 송수신을 위한 네트워크 연결 의사가 있음을 알리는 것이다.
    • 그 대상(서버)이 요청을 받아들일 준비가 되어있지 않다면 요청은 무시되기 때문에 어떤 연결 요청을 받아들일 것인지 미리 알고 등록해야 한다.
    • 연결을 요청하는 쪽이 클라이언트 소켓, 받아들이는 쪽이 서버 소켓이다.
    • 서버 소켓은 연결 요청을 받아들이는 연할만 수행할 뿐 새로 만들어지는 소켓으로 데이터를 통신한다.

    참고
    소켓 프로그래밍

    4.2 TCP의 성능에 대한 고려

    • HTTP는 TCP 바로 위에 있는 계층이기 때문에, HTTP 트랜잭션의 성능은 TCP 성능에 영향을 받는다.

    1) HTTP 트랜잭션 지연

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

    1. 클라이언트는 URI에서 웹 서버의 IP 주소와 포트 번호를 알아내야 한다. 만약 URI에 기술되어 있는 호스트에 방문한 적이 없으면, DNS 이름 분석 인프라를 사용하여 URI에 있는 호스트 명을 IP 주소로 변환하는데 수십 초의 시간이 걸릴 것이다. (현재는 인프라의 발전으로 밀리초 단위로 DNS 이름 분석이 끝난다.)
    2. 클라이언트는 TCP 커넥션 요청을 서버에게 보내고 서버가 커넥션 허가 응답을 회신하기를 기다린다.
    3. 커넥션이 맺어지면 클라이언트는 HTTP 요청을 새로 생성된 TCP 파이프를 통해 전송, 웹 서버는 도착하는 대로 TCP 커넥션에서 요청 메시지를 읽고 처리한다.
    4. 웹 서버가 HTTP 응답을 보내는 것 역시 시간이 소요된다.

    건너뛰기 !!

    2) 성능 관련 중요 요소

    HTTP 프로그래머에게 영향을 주는 가장 일반적인 TCP 관련 지연들

    • TCP 커넥션의 핸드셰이크 설정
    • 인터넷의 혼잡을 제어하기 위한 TCP의 느린 시작(slow-start)
    • 데이터를 한데 모아 한 번에 전송하기 위한 네이글(nagle) 알고리즘
    • TCP의 편승(piggyback) 확인응답(acknowledgment)을 위한 확인응답 지연 알고리즘
    • TIME_WAIT 지연과 포트 고갈

    고성능의 HTTP 소프트웨어를 개발하고 있는것이 아니라면 건너뛰어도 좋다.

    3) TCP 커넥션 핸드셰이크 지연

    4) 확인응답 지연

    5) TCP 느린 시작(slow start)

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

    7) TIME_WAIT의 누적과 포트 고갈

    4.3 HTTP 커넥션 관리

    1) 흔히 잘못 이해하는 Connection 헤더

    • HTTP 메시지는 클라이언트에서 서버까지 중개 서버들을 하나하나 거치면서 전달된다.
    • 두 개의 인접한 HTTP 애플리케이션이 현재 맺고 있는 커넥션에만 적용될 옵션을 지정해야 할 때가 있다.
    • HTTP Connection 헤더 필드는 커넥션 토큰을 쉼표로 구분하여 가지고 있으며, 그 값들은 다른 커넥션에 전달되지 않는다.
    • Connection 헤더에는 다음 세 가지 종류의 토큰이 전달될 수 있기 때문에 다소 혼란스러울 수 있다.
      1. HTTP 헤더 필드 명은, 이 커넥션에만 해당되는 헤더들을 나열한다.
      2. 임시적인 토큰 값은, 커넥션에 대한 비표준 옵션을 의미한다.
      3. close 값은, 커넥션의 작업이 완료되면 종료되어야 함을 의미한다.
    • Connection 헤더에 있는 모든 헤더 필드는 메시지를 다른곳으로 전달하는 시점에 삭제되어야 한다.

      HTTP/1.1 200 OK
      Connection: meter, close, bill-my-credit-card
      Meter: max-uses=3, max-refuses=6, dont-report

      Conneciton 헤더는 Meter 헤더를 다른 커넥션으로 전달하면 안되고 'bill-my-credit-card' 옵션을 적용할 것이며
      이 트랜잭션이 끝나면 커넥션이 끊길 것이라고 말한다.

    • Connection 헤더가 포함된 메시지를 전달받은 HTTP 애플리케이션은 요청에 기술되어 있는 모든 옵션을 적용한다.
    • 다음 홉에 메시지를 전달하기 전에 Conneciton 헤더와 Connection 헤더에 기술되어 있던 모든 헤더를 삭제한다.

      홉이란 각 서버를 의미하며 홉별은 특정 두 서버 간에만 영향을 미치고 다른 서버 간에는 영향을 미치지 않음을 의미

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

    • 웹 페이지에 세 개의 이미지 파일이 있다고 가정할 때, 브라우저가 이 페이지를 보여주려면 네 개의 HTTP 트랜잭션을 만들어야 한다.
    • 각 트랜잭션이 새로운 커넥션을 필요로 한다면, 커넥션을 맺는데 발생하는 지연과 함께 느린 시작 지연이 발생할 것이다.
    • 순차적인 처리는 물리적 지연뿐 아니라, 하나의 이미지를 내려받는 동안 웹페이지의 나머지 공간에 아무런 변화가 없어서 생기는 심리적 지연도 있다.

    HTTP 커넥션의 성능을 향상시킬 수 있는 최신 기술 네 가지

    1. 병렬(parallel) 커넥션
      여러 개의 TCP 커넥션을 통한 동시 HTTP 요청
    2. 지속(persistnet) 커넥션
      커넥션을 맺고 끊는 데서 발생하는 지연을 제거하기 위한 TCP 커넥션의 재활용
    3. 파이프라인(pipelined) 커넥션
      공유 TCP 커넥션을 통한 병렬 HTTP 요청
    4. 다중(multiplexed) 커넥션
      요청과 응답들에 대한 중재 (실험적인 기술이다)

    4.4 병렬 커넥션

    • HTTP는 클라이언트가 여러 개의 커넥션을 맺음으로써 여러 개의 HTTP 트랜잭션을 병렬로 처리할 수 있게 한다.

    이미지같은 내부 객체에 대한 HTML 태그에 폭과 높이 속성을 기술하면 레이아웃 지연을 없앨 수 있다.
    브라우저는 서버에 객체들을 내려받기 전에 레이아웃을 그릴 수 있다.

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

    • 단일 커넥션의 대역폭 제한과 커넥션이 동작하지 않고 있는 지연시간을 활용하면 여러개의 객체가 있는 웹 페이지를 더 빠르게 내려받을 수 있음

    대역폭(신호 처리)이란?
    통신 시스템의 자료 전송율 또는 특정한 기능을 수행할 수 있는 주파수 범위
    대역폭은 한 가지로 정확하게 정의하기 힘든 개념이며, 주파수 영역에서 특정 기능이 얼마나 넓은 범위 안에서 동작하는 지를 나타내는 모호한 개념

    대역폭 제한?
    인터넷 서비스 공급자가 의도적으로 인터넷 서비스를 느리게 하는것.
    대역폭 제한은 네트워크의 과부하를 막아 Quality of Service를 보장하는데 도움이 되고, 네트워크 트래픽을 규제하는 방법 중 하나이다.

    • 각 커넥션의 지연 시간을 겹치게 하면 총 지연 시간을 줄일 수 있다.
    • 클라이언트의 인터넷 대역폭을 한 개의 커넥션이 다 써버리는 것이 아니라면 나머지 객체를 내려받는 데에 남은 대역폭을 사용할 수 있다.

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

    • 클라이언트의 네트워크 대역폭이 좁을 때(예를들어, 브라우저가 28.8Kbps 모뎀으로 인터넷에 연결되어 있는 경우) 대부분 시간을 데이터 전송하는데만 쓸 것이다.
    • 여러개의 객체를 병렬로 내려받는 경우, 이 제한된 대역폭 내에서 각 객체를 전송받는 것은 느리기 때문에 성능상의 장점이 거의 없어진다.
    • 브라우저는 실제로 병렬 커넥션을 사용하긴 하지만 적은 수(대부분 6~8개)의 병렬 커넥션만을 허용한다.
    • 서버는 특정 클라이언트로부터 과도한 수의 커넥션이 맺어졌을 경우, 그것을 입의로 끊어버릴 수 있다.

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

    • 병렬 커넥션이 실제로 페이지를 더 빠르게 내려받는 것은 아니지만, 화면에 여러 개의 객체가 동시에 보이면서 내려받고 있는 상황을 볼 수 있기 때문에 사용자는 더 빠르게 내려받고 있다고 느낄 수 있다.

    4.5 지속 커넥션

    • 하나의 웹 페이지에 첨부된 이미지들이나 하이퍼링크들은 대부분 같은 웹 사이트를 가리킨다.
    • 서버에 HTTP 요청을 하기 시작한 애플리케이션은 같은 서버에 또 요청하게 되는데 이것을 지역성(site locality)이라 부른다.
    • 따라서 HTTP/1.1을 지원하는 기기는 처리가 완료된 후에도 TCP 커넥션을 유지하여 다음 요청에도 재사용 할 수 있는데, 이것을 지속 커넥션이라 부른다.
    • 지속 커넥션을 재사용함으로써, 커넥션을 맺기 위한 준비작업 시간을 절약할 수 있다.

    1) 지속 커넥션 vs 병렬 커넥션

    • 병렬 커넥션의 단점
      1. 각 트랜잭션마다 새로운 커넥션을 맺고 끊기 때문에 시간과 대역폭이 소요된다.
      2. 각각의 새로운 커넥션은 TCP 느린 시작 때문에 성능이 떨어진다.
      3. 실제로 연결할 수 있는 병렬 커넥션의 수에는 제한이 있다.
    • 지속 커넥션의 장점
      1. 커넥션을 맺기 위한 사전 작업과 지연을 줄여주고, 튜닝된 커넥션을 유지하며, 커넥션의 수를 줄여준다.

        튜닝된 커넥션이란?
        TCP 느린 시작에서, 패킷을 수차례 성공적으로 전송한 결과로 한 번에 다수의 패킷을 전송할 수 있는 권한을 얻은 커넥션

    • 두 가지를 함께 사용할 때 가장 효과적이기 때문에 오늘날 많은 웹 애플리케이션은 적은 수의 병렬 커넥션만을 맺고 그것을 유지한다.

    2) HTTP/1.0+의 Keep-Alive 커넥션

    • 많은 HTTP/1.0 브라우저와 서버들은 일찍부터 다소 실험적이었던 keep-alive 커넥션이라는 지속 커넥션을 지원하기 위해 확장되었다.
    • 초기의 지속 커넥션은 설계상의 문제가 있었지만, HTTP/1.1에 수정되었다.

    3) Keep-Alive 동작

    • keep-alive는 사용하지 않기로 결정되어 HTTP/1.1 명세에는 빠졌지만, 아직 브라우저와 서버간 keep-alive Handshake가 널리 사용되고 있기 때문에, HTTP 애플리케이션은 그것을 처리할 수 있게 개발해야 한다.
    • 클라이언트는 커넥션을 유지하기 위해서 요청에 Connection: Keep-Alive 헤더를 포함시킨다.
    • 요청을 받은 서버는 다음 요청도 같은 커넥션으로 받고자 한다면 응답에 똑같은 헤더를 포함 시켜야 한다.
    • 응답에 Connection: Keep-Alive 헤더가 없으면 클라이언트는 서버가 keep-alive를 지원하지 않으며 커넥션이 끊길 것이라 생각한다.

    4) Keep-Alive 옵션

    • 클라이언트나 서버는 keep-alive 요청을 받았다고 해서 무조건 따를 필요가 없으며 언제든지 커넥션을 끊을 수 있고, keep-alive에서 처리되는 트랜잭션의 수를 제한할 수도 있다.
    • keep-alive의 동작은 Keep-Alive 헤더의 쉼표로 구분된 옵션들로 제어할 수 있다.
      1. timeout: 커넥션이 얼마간 유지될 것인지를 의미
      2. max: 커넥션이 몇 개의 HTTP 트랜잭션을 처리할 때까지 유지될 것인지 의미
    • Keep-Alive 헤더 사용은 선택 사항이지만, Connection: Keep-Alive 헤더가 있을 때만 사용할 수 있다.

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

    5) Keep-Alive 커넥션 제한과 규칙

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

    Connection 헤더의 무조건 전달

    • 프락시는 Conenction 헤더를 이해하지 못해서 해당 헤더들을 삭제하지 않고 요청 그대로를 다음 프락시에 전달한다.
    • 웹 클라이언트가 무조건 전달을 하는 멍청한 프락시를 거쳐 웹 서버에 메시지를 전송했을 때 상황
      1. 웹 클라이언트는 프락시에 Connection: Keep-Alive 헤더와 함께 메시지를 보내고 커넥션 유지 요청에 대한 응답을 기다린다.
      2. 멍청한 프락시는 keep-alive를 이해하지 못하고 다음 서버로 메시지를 그대로 전달한다.
        하지만 Connection 헤더는 홉별 헤더(다음 서버로 전송되면 안되는 헤더)이기 때문에 여기부터 문제가 발생한다.
      3. 웹 서버가 프락시로부터 Connection: Keep-Alive 헤더를 받으면, 웹 서버는 프락시가 커넥션을 유지하자고 요청하는 것으로 잘못 판단한다.
        웹 서버는 프락시와 커넥션을 유지하는 것에 동의를 하고 Connection: Keep-Alive 헤더를 포함하여 응답한다.
        웹 서버는 프락시와 keep-alive 커넥션이 맺어져 있는 상태로 판단하여 그에 대한 규칙에 맞게 통신하지만 프락시는 keep-alive를 전혀 이해하지 못한다.
      4. 멍청한 프락시는 서버로부터 받은 Connection: Keep-Alive 헤더를 포함한 응답을 클라이언트에게 전달한다.
        클라이언트와 서버는 서로 keep-alive에 동의했다고 생각하지만 프락시는 이 상황을 전혀 이해하지 못한다.
      5. 프락시는 응답을 클라이언트에게 전달한 후 서버가 커넥션을 끊기를 기다린다.
        하지만 서버는 커넥션을 유지하는 것으로 알고 있기 때문에 커넥션을 끊지 않고 프락시는 계속 기다린다.
      6. 클라이언트는 다음 요청을 프락시에게 보내기 시작하는데, 프락시는 다음 요청이 오는 것을 예상하지 못하기 때문에,
        그 요청은 프락시로부터 무시되고 브라우저는 응답을 계속 기다리게된다.
      7. 이런 잘못된 통신 때문에, 브라우저는 자신이나 서버가 타임아웃이 나서 커넥션이 끊길 때까지 기다린다.

    프락시와 홉별 헤더

    • 이런 종류의 잘못된 통신을 피하려면, 프락시는 Connection 헤더와 그에 명시된 헤더들은 절대 전달하면 안된다.
    • 또한 Proxy-Authenticate, Proxy-Connection, Transfer-Encoding, Upgrade와 같은 홉별 헤더 역시 전달하면 안된다.

    7) Proxy-Connection 살펴보기

    • 넷스케이프는 멍청한 프락시 문제를 해결하기 위해 브라우저에서 일반적으로 전달하는 Connection 헤더 대신에 비표준인 Proxy-Connection 확장 헤더를 프락시에게 전달한다.
    • 멍청한 프락시가 Proxy-Connection를 웹 서버에 보내더라도 웹 서버는 그것을 무시하기 때문에 별 문제가 되지 않는다.
    • 영리한 프락시는 Proxy-Connection 헤더를 인식하고 서버로 Connection: Keep-Alive 헤더를 전달한다.
    • 멍청한 프락시의 양옆에 영리한 프락시가 있다면 잘못된 헤더를 만들어내는 문제가 발생한다.
    • 문제를 발생시키는 프락시들은 네트워크상에서 '보이지 않는' 경우가 많기 때문에 브라우저는 Proxy-Connection 헤더를 보낼 수 없다.

    8) HTTP/1.1의 지속 커넥션

    • HTTP/1.1에서는 keep-alive 대신 설계가 더 개선된 지속 커넥션을 지원한다.
    • keep-alive와 달리 지속 커넥션은 기본적으로 활성화되어 있다. (별도의 설정을 하지 않는 한 모든 커넥션은 지속 커넥션)
    • HTTP/1.1 애플리케이션은 지속 커넥션은 끊으려면 Conneciton: close 헤더를 명시해야 한다.
    • Connection: close 헤더가 없으면 응답 후에도 커넥션은 유지하자는 것으로 추정하지만 클라이언트와 서버는 언제든 커넥션을 끊을 수 있다.

    9) 지속 커넥션의 제한과 규칙

    • 클라이언트가 요청에 Connection: close 헤더를 포함해 보냈으면, 클라이언트는 그 커넥션으로 추가적인 요청을 보낼 수 없다.
    • 클라이언트는 추가적인 요청이 없다면 마지막 요청에 Connection: close 헤더를 포함해 보내야 한다.
    • 커넥션에 있는 모든 메시지는 엔터티 본문의 정확한 Content-Length 값을 가지거나 청크 전송 인코딩으로 인코드 되어 있어야 한다.
    • HTTP/1.1 프락시는 클라이언트가 서버 각각에 대해 별도의 지속 커넥션을 맺고 관리해야 한다.
    • HTTP/1.1 프락시 서버는 클라이언트가 커넥션 관련 기능에 대한 클라이언트의 지원 범위를 알고 있지 않은 한 지속 커넥션을 맺으면 안된다.
    • HTTP/1.1 기기는 Connection 헤더의 값과는 상관없이 언제든지 커넥션을 끊을 수 있다.
    • HTTP/1.1 애플리케이션은 중간에 끊어지는 커넥션을 복구할 수 있어야 하고, 클라이언트는 다시 보낼 수 있는 요청이라면 다시 보내야 한다.
    • 하나의 클라이언트는 서버 과부하 방지를 위해 두개 이상의 지속 커넥션을 유지해야 한다.(N명의 사용자가 서버로 접근한다면 2N개의 커넥션 유지)

    4.6 파이프라인 커넥션

    파이프라인의 제약 사항

    • HTTP 클라이언트는 커넥션이 지속 커넥션인지 확인하기 전까지는 파이프라인을 이어서는 안된다.
    • HTTP 응답은 요청의 순서와 같게 들어와야 한다. HTTP 메시지는 순번이 없기 때문에 제 각각 오면 정렬시킬 방법이 없다.
    • 클라이언트가 지속 커넥션은 맺고 10개의 요청을 보냈을 때 서버는 5개만 처리하고 커넥션을 끊을 수 있는데, 클라이언트는 이 커넥션은 다시 맺고 요청을 보낼 수 있어야 한다.
    • HTTP는 POST와 같은 비멱등 메서드는 반복 요청시 문제가 생길 수 있기 때문에 파이프라인을 통해 보내면 안된다.

      비멱등이란?
      POST는 보통 회원가입이나 글 작성 등에 사용하는 HTTP 메서드이기 때문에 요청을 보낼 때마다 서버에 변화가 생긴다.
      반면 GET 메서드는 여러번 요청을 하여도 서버에 변화가 생기지 않기 때문에 멱등이라고 할 수 있다.

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

    • 커넥션 관리(특히 언제 어떻게 커넥션을 끊는가)에는 명확한 기준이 없다.
    • 이 이슈는 수많은 개발자가 알고 있는 것보다 더 미묘하며, 그에 관한 기술 문서도 별로 없다.

    1) '마음대로' 커넥션 끊기

    • HTTP 클라이언트, 서버, 혹은 프락시는 언제든지 TCP 전송 커넥션을 끊을 수 있다.
    • 보통 커넥션은 메시지를 다 보낸 다음 끊지만, 에러가 있는 상황에서는 헤더의 중간이나 다른 엉뚱한 곳에서 끊길 수 있다.
    • 지속 커넥션이 일정 시간 동안 요청을 전송하지 않고 유휴 상태에 있으면 서버는 그 커넥션을 끊을 수 있다.
    • 하지만 서버가 유휴 상태에 있는 커넥션을 끊는 시점에, 서버는 클라이언트가 다시 요청하지 않을 것이라고 확신하지 못한다. 클라이언트가 다음 요청을 보낸다면 문제가 생긴다.

    2) Content-Length와 Truncation

    • 각 HTTP 응답은 본문의 정확한 크기 값을 가지는 Content-Length 헤더를 가지고 있어야 한다.
    • 클라이언트나 프락시가 커넥션이 끊어졌다는 HTTP 응답을 받은 후, 실제 전달 된 엔터티 본문의 길이와 Content-Length가 일치하지 않거나 Content-Length 헤더가 존재하지 않는다면 수신자는 데이터의 정확한 길이를 서버에게 물어봐야 한다.
    • 만약 수신자가 캐시 프락시일 경우 응답을 캐시하면 안되며, Content-Length를 정정하려 하지 말고 메시지를 받은 그대로 전달해야 한다.

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

    • 커넥션은 에러가 없더라도 언제든 끊을 수 있다.
    • HTTP 애플리케이션은 예상치 못하게 커넥션이 끊어졌을 경우를 대응할 수 있도록 준비해야 한다.
    • 클라이언트는 트랜잭션 수행 중 커넥션이 끊어졌을 때 다시 트랜잭션을 전송해도 문제가 없다면 커넥션은 다시 맺고 한번 더 전송해야 한다.
    • GET 요청은 반복적으로 요청하더라도 결과적으로 아무런 영향을 끼치지 않지만, 온라인 서점에서 주문을 하는 POST 요청은 반복할 경우 여러 번 주문이 될 것이기 때문에 반복은 피해야 한다.
    • 한 번 혹은 여러 번 실행해도 같은 결과를 반환한다면 그 트랜잭션은 멱등(idempotent)하다고 한다.
    • GET, HEAD, PUT, DELETE, TRACE, OPTIONS 메서드들은 멱등
    • POST와 같은 비멱등 메서드는 파이프라인을 통해 요청하면 안된다.
    • 비멱등 요청을 다시 보내야 한다면, 이전 요청에 대한 응답을 받을 때까지 기다려야 한다.
    • 비멱등 메서드나 순서에 대해 에이전트가 요청을 다시 보낼 수 있도록 기능을 제공할 때 자동으로 재시도하면 안된다. 캐시된 POST 요청 페이지를 다시 로드하려고 할 때, 요청을 다시 보내기를 원하는지 묻는 대화상자를 보여준다.

    4) 우아한 커넥션 끊기

    • TCP 커넥션은 양방향이며 양쪽에는 데이터를 읽거나 쓰기 위한 입력 큐와 출력 큐가 있다. 한쪽 출력 큐에 있는 데이터는 다른 쪽의 입력 큐에 보내질 것이다.

    전체 끊기와 절반 끊기

    • 애플리케이션은 TCP 입력 채널과 출력 채널 중 한 개만 끊거나 둘 다 끊을 수 있다.
    • close()를 호출하면 TCP 커넥션의 입력 채널과 출력 채널의 커넥션을 모두 끊는다. (전체 끊기)
    • shutdown()을 호출하면 입력 채널이나 출력 채널 중 하나를 개별적으로 끊을 수 있다. (절반 끊기)

    TCP 끊기와 리셋 에러

    • 단순한 HTTP 애플리케이션은 전체 끊기만을 사용할 수 있다.
    • 하지만 애플리케이션은 다른 애플리케이션들과 통신할 때, 그리고 그들과 파이프라인 지속 커넥션을 사용할 때, 기기들에 예상치 못한 쓰기 에러를 발생하는 것을 예방하기 위해 '절반 끊기'를 사용해야 한다.
    • 보통은 커넥션의 출력 채널을 끊는 것이 안전하다.
    • 클라이언트에서 이미 끊긴 입력 채널에 데이터를 전송하면, 서버의 운영체제는 TCP 'connection reset by peer' 메시지를 클라이언트에게 보낸다.
    • 대부분 운영체제는 이것을 심각한 에러로 취급하여 버퍼에 저장된, 아직 읽히지 않은 데이터를 모두 삭제한다.

    우아하게 커넥션 끊기

    • 우아한 커넥션 끊기를 구현하는 것은 애플리케이션 자신의 출력 채널을 먼저 끊고 다른 쪽에 있는 기기의 출력 채널을 끊기는 것을 기다리는 것
      이다.
    반응형
Designed by Tistory.