HTTP란?

  • HTTP는 웹상에서 Client (Internet Explorer, Chrome, Firefox) 와 Server (웹서버 eg: httpd, nginx, etc…)간 통신을 위한 Protocol 입니다.
  • HTTP는 1996년 처음 1.0버전이 release되고 1999년 현재 우리가 공식적으로 가장 많이 사용하고 지원하는 버전인 1.1이 출시된 이후 15년동안 발전없이 사용되고 있습니다.

HTTP/0.9

  • HTTP/0.9는 GET 메소드만 사용하는 아주 단순한 프로토콜입니다. HTML만 전송이 가능합니다.

HTTP/1.0

  • HTTP/1.0에서 헤더가 추가되고 핸드쉐이크가 도입되었습니다.
  • HTTP/1.0은 기본적으로 Connection 당 하나의 요청을 처리 하도록 설계 되어 있습니다. 그래서 위 그림과 같이 동시전송이 불가능하고 요청과 응답이 순차적으로 이루어 지게 됩니다. 그렇다 보니 HTTP 문서안에 포함된 다수의 리소스(Images, CSS, Script)를 처리하려면 요청할 리소스 개수에 비례해서 Latency(대기 시간)는 길어지게 됩니다.
    • http/1.0의 경우 일반적으로 하나의 connection에 하나의 요청을 처리 합니다. 이렇다 보니 매 요청별로 connection을 만들게 되고 TCP상에서 동작하는 HTTP의 특성상 3-way Handshake가 반복적으로 일어나고 또한 불필요한 RTT(Round Trip Time)증가와 네트워크 지연을 초래하여 성능을 저하 시키게 됩니다.
  • Keep-Alive가 도입되었지만 표준이 아니라서 프록시 벤더사 마다 지원하기도 안하기도 했습니다.

HTTP/1.1

http1 1

  • HTTP/1.1에서 Keep-Alive가 아닌 지속 커넥션을 도입하여 요청을 열어 두는 것이 가능해졌습니다. 하지만 다음 요청을 보내기 위해서 이전 요청이 도착해야합니다.
  • 파이프라인 기법을 도입해 큐를 활용해 순차적으로 처리합니다. 하지만 처음 요청이 문제가 발생하면 병목 현상(Head Of Line Blocking)이 발생합니다.
  • 무거운 Header 구조(특히 Cookie) 문제가 있습니다. 어쩔땐 요청을 통해서 전송하려는 값보다 헤더 값이 더 큰경우도 비일비재 합니다.

HTTP의 HOL Blocking

  • 순서대로 첫번째 이미지를 요청하고 응답받고 다음 이미지를 요청하게 되는데 만약 첫번째 이미지를 요청하고 응답이 지연되면 두,세번째 이미지는 당연히 첫번째 이미지의 응답처리가 완료되기 전까지 대기하게 되며 이와 같은 현상을 HTTP의 Head of Line Blocking 이라 부르며 파이프 라이닝의 큰 문제점 중 하나 입니다.

1.1에서의 문제를 해결하기 위한 방법

  • Domain Sharding
    • 요즘 브라우저들은 http/1.1이 단점을 극복하기 다수의 Connection을 생성해서 병렬로 요청을 보내기도 합니다. 하지만 브라우저 별로 Domain당 Connection개수의 제한이 존재하고 이 또한 http/1.1의 근본 해결책은 아닙니다.
  • Minify CSS/Javascript
    • http를 통해서 전송되는 데이터의 용량을 줄이기 위해 CSS, Javascript 코드를 축소하여 적용하기도 합니다.
  • Data URI Scheme
    • Data URI 스킴은 HTML문서내 이미지 리소스를 Base64로 인코딩된 이미지 데이터로 직접 기술하는 방식이고 이를 통해 요청 수를 줄이기도 합니다.
  • Load Faster
    • 스타일시트를 HTML 문서 상위에 배치합니다.
    • 스크립트를 HTML문서 하단에 배치합니다.

SPDY

  • 구글은 더 빠른 Web을 실현하기 위해 throughput 관점이 아닌 Latency 관점에서 HTTP를 고속화한 SPDY(스피디)라 불리는 새로운 프로토콜을 구현하였습니다. 다만 SPDY는 HTTP를 대치하는 프로토콜이 아니고 HTTP를 통한 전송을 재 정의하는 형태로 구현이 되었습니다.
  • SPDY는 실제로 HTTP/1.1에 비해 상당한 성능 향상과 효율성을 보여줬고 이는 HTTP/2 초안의 참고 규격이 되게 됩니다.

HTTP/2(HTTP over SPDY)

  • HTTP/2는 앞서 설명한것 처럼 SPDY를 기반으로 http2 작업그룹이 2012년 10월 부터 시작한 새로운 프로토콜 구현 프로젝트 입니다.
  • HTTP/2에서는 보내야 할 데이터를 바이너리로 변환하는 계층이 있기 때문에 단순 텍스트를 전송하는 것보다 훨씬 더 효율적으로 데이터를 전송할 수 있습니다. 이것은 사실 HTTP/2의 버전이 HTTP/1.2가 아닌 이유이기도 한데, 예전처럼 텍스트 기반의 전송이 아닌 바이너리 프레이밍을 사용하기 때문이라고 합니다.
  • HTTP/2는 HTTP가 유선상에서 표현 방법을 대치 하는것입니다. 이것은 프로토콜을 완전히 다시 작성하는게 아니라 HTTP 메소드, 상태 코드 및 의미는 동일하며 프로토콜을 나타내기 위해 HTTP/ 1.x와 동일한 API(일부 작은 추가 기능 포함)를 사용 할 수 있어야 합니다.
  • HTTP/2의 초점은 성능에 있습니다. 특히 최종 사용자가 대기 시간, 네트워크 및 서버 리소스 사용을 인식합니다.
  • HTTP/2에서는 핸드쉐이크를 최소화하기 위해서 단일 TCP 연결을 유지하면서 여러 개의 요청을 처리할 수 있도록 변경 되었습니다.
    • Multiplexed Streams : 한 커넥션으로 동시에 여러개의 메세지를 주고 받을 있으며, 응답은 순서에 상관없이 stream으로 주고 받습니다. HTTP/1.1의 Connection Keep-Alive, Pipelining의 개선이라 보면 됩니다.
    • Stream Prioritization : 클라이언트가 요청한 HTML문서안에 CSS파일 1개와 Image파일 2개가 존재하고 이를 클라이언트가 각각 요청하고 난 후 Image파일보다 CSS파일의 수신이 늦어지는 경우 브라우저의 렌더링이 늦어지는 문제가 발생하는데 HTTP/2의 경우 리소스간 의존관계(우선순위)를 설정하여 이런 문제를 해결하고 있습니다.
    • Header Compression : HTTP/2는 Header 정보를 압축하기 위해 Header Table과 Huffman Encoding 기법을 사용하여 처리하는데 이를 HPACK 압축방식이라 부르며 별도의 명세서(RFC 7531)로 관리하고 있습니다. 클라이언트가 두번의 요청을 보낸다고 가정하면 HTTP/1.x의 경우 두개의 요청 Header에 중복값이 존재해도 그냥 중복 전송합니다. 하지만 HTTP/2에선 Header에 중복값이 존재하는 경우 Static/Dynamic Header Table 개념을 사용하여 중복 Header를 검출하고 중복된 Header는 index값만 전송하고 중복되지 않은 Header정보의 값은 Huffman Encoding 기법으로 인코딩 처리 하여 전송합니다.
    • Server Push : 서버는 클라이언트의 요청에 대해 요청하지도 않은 리소스를 마음대로 보내줄 수도 있습니다. 클라이언트(브라우저)가 HTML문서를 요청했고 해당 HTML에 여러개의 리소스(CSS, Image…) 가 포함되어 있는경우 HTTP/1.1에서 클라이언트는 요청한 HTML문서를 수신한 후 HTML문서를 해석하면서 필요한 리소스를 재 요청하는 반면 HTTP/2에선 Server Push기법을 통해서 클라이언트가 요청하지도 않은 (HTML문서에 포함된 리소스) 리소스를 Push 해주는 방법으로 클라이언트의 요청을 최소화 해서 성능 향상을 이끌어 냅니다. 이를 PUSH_PROMISE 라고 부르며 PUSH_PROMISE를 통해서 서버가 전송한 리소스에 대해선 클라이언트는 요청을 하지 않습니다.
  • 결국 HTTP/1에서 HTTP/2로 넘어갈 때도 핸드쉐이크 과정 자체는 건드리지 않았고 단지 핸드쉐이크가 발생하는 횟수를 최소화함으로써 레이턴시를 줄인 것입니다. 이는 TCP를 사용하는 이상 핸드쉐이크가 반드시 필요한 과정이기 때문에 건드리지 못한 것입니다.
  • 패킷이 처리되는 순서 또한 정해져있으므로 이전에 받은 패킷을 파싱하기 전까지는 다음 패킷을 처리할 수도 없습니다. 이렇게 패킷이 중간에 유실되거나 수신 측의 패킷 파싱 속도가 느리다면 통신에 병목이 발생하게 되는 현상을 HOLB(Head Of Line Blocking)라고 부릅니다. 이건 TCP 자체의 문제이므로 HTTP/1 뿐만 아니라 HTTP/2도 가지고 있는 문제입니다.

QUIC

  • UDP 기반의 전송 계층 프로토콜 입니다.
  • 2013년에 구글에서 공개되었습니다.
  • 전송 속도를 향상 시켰습니다.
    • UDP는 TCP와 다르게 별도의 기능이 없기 때문에 원하는 기능을 구현하기 좋습니다.
    • 첫 연결 설정에서 필요한 정보와 함께 데이터를 전송합니다. 연결 성공 시 설정을 캐싱하여 다음 연결 때 바로 사용 가능합니다.
  • Connection UUID라는 고유한 식별자로 서버와 연결하기 때문에 커넥션 재수립이 필요하지 않습니다.
  • TLS를 기본 적용하고 있습니다.
  • IP Spoofing / Replay Attack 방지를 통해 보안성을 향상 시킵니다.
  • 독립 스트림을 통해 향상된 멀티플렉싱을 지원합니다.
  • 어플리케이션 계층에 신뢰성을 구현합니다.

HTTP/3(HTTP over QUIC)

  • 2018년 11월에 QUIC를 기반으로 HTTP/3을 공개했습니다.
  • HTTP/3는 UDP를 사용함으로써 이 핸드쉐이크 과정 자체를 날려버리고 Connection UUID으로 연결의 신뢰성을 확보함으로써 레이턴시를 줄이는 방법을 택했습니다.
    • HTTP/3는 IP 기반이 아닌, 연결 별 고유 UUID(Connection ID)를 이용해 각 연결을 식별합니다. TCP 기반 통신의 경우에는 Wi-Fi 환경에서 셀룰러 환경으로 이동하는 경우 IP 주소가 변경되기 때문에 연결 재수립 과정을 거쳐야 하지만, QUIC은 연결 ID 기반으로 식별하기 때문에 연결을 그대로 유지할 수 있습니다.
  • HTTP/3는 연결 정보를 캐싱하여 재사용할 수 있는 0-RTT 기능을 제공합니다. TCP의 경우 최초 연결 수립 시 3-way 핸드셰이크 과정이 필요하지만, HTTP/3는 최초 연결 설정에서 연결에 필요한 정보들과 데이터를 함께 전송하여 1-RTT로 시간을 절약합니다. 또한 한 번 성공한 연결은 캐싱해놓다가 다음 연결 때에는 캐싱된 정보를 바탕으로 바로 연결을 수립할 수 있기 때문에 0-RTT가 가능합니다.
  • HTTP/3는 연결 다중화를 지원하며, 각 스트림이 독립적으로 동작합니다. HTTP/2에서는 연결 다중화가 지원되어 여러 스트림을 동시에 지원할 수 있지만, TCP 특성상 데이터 손실이 발생하면 데이터 복구를 우선 처리하면서 HOLB가 발생합니다. 하지만 QUIC 기반의 HTTP/3는 연결 내 스트림이 완전히 독립적으로 동작하기 때문에 데이터 손실이 발생해도 다른 스트림에 영향을 주지 않습니다.
  • HTTP/2와 마찬가지로 TLS 연결 설정 과정이 QUIC 내부에 포함되기 때문에 HTTP/3는 HTTPS 사용이 강제되고, 우선순위 제어, 서버 푸시 등의 기능을 제공합니다.
  • HTTP/3의 헤더 프레임은 HTTP/2.0의 HPACK과 유사하게 QPACK을 이용해 압축되어 전송됩니다. QUIC의 스트림이 독립적으로 송수신함에 따라 이에 맞춰 개선된 것 정도로 이해하면 됩니다.
  • 기존 HTTP 체계와 호환되기 때문에, TCP 기반 통신 중 HTTP/3가 지원된다면 서버가 이를 클라이언트 측에 이를 알려 HTTP/3 방식의 통신으로 전환을 유도할 수 있기도 합니다.

TCP와 UDP의 차이

TCP UDP
연결방식 연결형 서비스 비연결형 서비스
패킷 교환 가상 회선 방식 데이터그램 방식
전송 순서 보장 보장함 보장하지 않음
신뢰성 높음 낮음
전송 속도 느림 빠름

HTTP 요약

  • HTTP/1.1: ASCII over TCP
  • HTTP/2: Binary Multiplexed over SPDY(TCP)
  • HTTP/3: Binary over Multiplexed QUIC(UDP)

METHOD

  • POST는 클라이언트가 리소스의 위치를 지정하지 않았을때 리소스를 생성하기 위해 사용하는 연산입니다. 이 연산은 idempotent하지 않습니다.
  • PUT은 리소스의 위치가 지정되었을때 생성 또는 업데이트를 위해 사용할 수 있습니다. idempotent합니다.
  • POST이나 POST 요청이 리소스를 새로 생성할 경우엔 리소스의 위치를 response header 의 Location field에 담아 201 Created 를 보낼 수 있습니다. 그러나 not-identifiable한 리소스를 생성할 경우엔 200 OK 또는 204 No Content를 보낼수도 있습니다.
  • 리소스를 수정하지 않는 메소드들, OPTIONS, GET, HEAD 등을 safe 하다고 말합니다. 대부분의 경우 idempotent 하면 safe합니다. 물론 예외도 있는데 DELETE는 idempotent 하지만 리소스를 변경하므로 safe 하지 않습니다. 자세한 내용은 RFC 7231: Safe Methods를 참고합니다. 참고로 RFC 7231은 PUT, DELETE와 safe methods를 idempotent 하다고 정의합니다.
  • 리소스는 주어진 URI에 대한 정보인데 OPTIONS는 정보를 가지고 오는 것이 아니라, 정보에 대해 어떤 연산이 가능한지를 알려줍니다. HTTP에서는 정보에 대해 캐싱하므로, GET이나 HEAD 같이 정보를 돌려주는 연산만 캐싱할 수 있습니다.
  • TRACE는 클라이언트가 방금 보낸 요청을 다시 달라고, 서버에게 요청하는 것이고 CONNECT 는 HTTP 터널링을 할때 쓰입니다. 중간의 프록시 서버를 위해서는 CONNECT로 요청하고, 마지막 프록시에서 end-point로는 GET 또는 CONNECT를 날립니다. HTTPS라면 CONNECT 를, HTTP라면 둘 중 아무거나 써도 상관 없습니다.
  • HTTP는 0.9 -> 1.0 -> 1.1 순으로 변화했다고 합니다. 0.9에선 GET을 이용한 Read-only 버전이었고 1.0 에 들어와서야 HEAD, POST 등을 이용해 서버로 데이터 전송이 가능해졌습니다. HTTP 1.1(RFC 2616)에 와서야 DELETE, PUT 등이 추가되면서 변경, 삭제까지 가능해졌습니다.

참고