Thumbnail

12분

HTTP... 그것에 대하여

HTTP는 월드 와이드 웹에 내재된 프로토콜 입니다.

WWW 발명

1989년, CERN에서 근무하던 Tim Berners-Lee는 인터넷 상의 하이퍼텍스트 시스템을 만들기 위한 제안을 작성했습니다. 이 시스템은 처음에는 Mesh라 불렸으며, 1990년 월드 와이드 웹(World Wide Web)으로 이름을 변경했습니다. 웹은 기존의 TCP/IP 프로토콜 위에서 구축되었으며, 4개의 주요 구성 요소를 가지고 있습니다.

  1. HTML: 하이퍼텍스트 문서를 표현하기 위한 텍스트 언어
  2. HTTP: 프로토콜
  3. 브라우저: 디스플레이를 위한 클라이언트
  4. 웹서버: 초기 버전의 httpd

1991년 9월 6일, Tim Berners-Lee가 alt.hypertext 공개 뉴스 그룹에 올린 포스트가 월드 와이드 웹의 공식적인 시작으로 간주됩니다.

HTTP vs TCP/IP

HTTP는 WWW에서 사용하고 있는 데이타 전송 프로토콜이며 MIME으로 지정할 수 있는 모든 데이타 형식에 대해 8bit 이진모드로 전송할 수 있습니다.
-HTTP vs. TCP/IP - w3

http-tcp-ip.gif

TCP/IP 프로토콜 위에서 HTTP가 설계되었기 때문에, 둘 사이의 관계는 매우 밀접합니다. (HTTP/3 프로토콜, 특히 QUIC은 UDP 프로토콜 위에서 설계되었기 때문에 달라질 수 있습니다.)

HTTP 프로토콜은 TCP/IP 프로토콜 체계에서 TELNET, FTP와 같은 응용 프로토콜 중 하나입니다.

TCP 전송 프로토콜을 이용하는 응용 프로토콜들 사이의 구별을 위해 port 번호를 통해 해결하고 있습니다.

HTTP 프로토콜 기본 동작

HTTP 프로토콜은 요청/응답(request/response) 방식을 사용하여 동작합니다.

원하는 프로토콜 기능(GET, HEAD, POST, PUT 등)에 대해 서비스 요구를 하면 데이터 송수신을 위한 TCP 연결이 만들어지고, 서버가 응답을 보내어 데이타 전송을 끝내면 자동적으로 연결이 끊어지게 되는 것입니다.

클라이언트와 서버 사이에 TCP 기반의 HTTP 연결을 만들고 요청 형식에 따라 서버에 메시지를 보냅니다. 서버는 요청 메시지를 읽고 그에 대한 응답 메시지를 보냅니다.

HTTP/0.9 : 원-라인 프로토콜

HTTP 초기 버전에는 프로토콜 이름이 붙어있지 않았습니다.
이후 버전과 구별하기 위해 0.9로 불리게 되었습니다.

  • 단일 라인으로 구성된 요청
  • 리소스에 대한 경로로 가능한 메소드는 GET이 유일

HTTP/0.9는 매우 간단한 프로토콜로, 단일 라인으로 구성된 요청과 GET 메소드만 사용 가능했습니다. 응답 역시 매우 단순하게 파일 내용 자체로 구성되었습니다. 이 때문에 HTML 파일만 전송 가능했습니다.

GET /mypage.html

응답 또한 극도로 단순합니다. 오로지 파일 내용 자체로 구성됩니다.

<html>
  A very simple HTML page
</html>

HTTP 헤더가 없었는데 이는 HTML 파일만 정송될 수 있으며, 다른 유형의 문서는 전송될 수 없음을 의미합니다.

상태, 오류 코드도 없었으며 만약 문제가 발생한 경우, HTML 파일 내부에 문제에 대한 설명과 함께 되돌려 보내졌었습니다.

HTTP/1.0 : 확장성 만들기

HTTP/0.9는 매우 제한적이었기 때문에 브라우저와 서버 모두 좀 더 빠르게 확장되었습니다.

  • 버전 정보 포함: HTTP/1.0 이 GET라인에 붙은 형태로
  • 상태 코드 포함: 응답의 시작 부분에 붙어 전송
  • HTTP 헤더 도입: 메타데이터 전송을 허용하고 프로토콜을 극도로 유연하고 확장가능하도록 만들어주었습니다.
  • HTML 파일 외 리소스 전달: Content-type 덕분에 HTML 파일 외에 리소스를 전송할 수 있는 기능이 추가되었습니다.

HTTP/1.0은 버전 정보, 상태 코드, HTTP 헤더를 도입하여 프로토콜을 더 유연하고 확장 가능하게 만들었습니다. 이로 인해 HTML 파일 외의 리소스도 전송할 수 있게 되었습니다.

# 첫 번째 요청
GET /mypage.html
HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
 
# 첫 번째 요청에 대한 응답
200 OK
Date: Tue, 15 Nov 1994 08:12:31 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/html
 
<html>
  A page with an image
  <img src="/myimage.gif" />
</html>

첫 번째 커넥션이 요청-응답 사이클을 거치고 끊어집니다. 이미지를 내려받기 위해 두 번째 커넥션에 대한 요청-응답 사이클을 거칩니다.

# 두 번째 요청
GET /myimage.gif HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
 
# 두 번째 요청에대한 응답
200 OK
Date: Tue, 15 Nov 1994 08:12:32 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/gif
 
(image content)

HTTP/1.0에서는 요청과 응답 모두에 버전 정보가 포함되었고, 상태 코드가 응답의 시작 부분에 추가되었습니다. HTTP 헤더의 도입으로 메타데이터를 전송할 수 있게 되었으며, Content-type을 통해 다양한 리소스를 전송할 수 있게 되었습니다.

이러한 새로운 기능들은 1991년부터 1995년 사이에 시행착오를 겪으며 도입되었습니다. 공식적인 표준이 없던 상태에서 진행되어 여러 문제가 발생했습니다. 이를 해결하기 위해 1996년 11월, RFC 1945 - HTTP/1.0이 발표되었습니다. 이것은 HTTP/1.0의 정의로, 공식적인 표준은 아니지만 그에 준하는 역할을 수행했습니다.

이후 HTTP/1.1과 HTTP/2.0 등의 버전이 등장했으며, 프로토콜의 성능과 기능이 개선되었습니다.

HTTP/1.1 - 표준 프로토콜

1995년 부터 다양한 곳에서 HTTP/1.0 구현이 동시에 진행되고 있었습니다.
그 이듬해 HTTP/1.0 문서(RFC1945) 출간 전까지, 합당한 표준화가 진행 중에 있었습니다.
HTTP의 첫 번째 표준 버전인 HTTP/1.1(RFC2068)은 HTTP/1.0이 나온지 몇 달 안되서 1997년 공개되었습니다.

HTTP/1.1은 모호함을 명확하게 하고 많은 개선 사항들을 도입했습니다.

  • 커넥션의 재사용: Keep-Alive 헤더 필드를 통해 단일 원본 문서 내 리소스들을 디스플레이 하기 위해 사용된 커넥션을 다시 열어 시간을 절약합니다.
  • 파이프라이닝: 첫 번째 요청에 대한 응답과 상관없이 두 번째 요청 전송을 가능케 합니다.
  • 청크된 응답, 지원: Transfer-Encoding 헤더 필드를 통해 나누어진(chunked) 리소스 전달이 가능합니다.
  • 추가적인 캐시 제어 메커니즘: Cache-Control 헤더 필드를 통한 제어
  • 가상 호스팅 : Host 헤더 필드 덕분에 동일 IP 주소에 다른 도메인을 호스트하는 기능을 사용할 수 있습니다.
# 첫 번째 요청 - Connection
GET /en-US/docs/Glossary/Simple_header HTTP/1.1
Host:developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header
 
# 첫 번째 요청에 대한 응답 - not close connection
200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html;
charset=utf-8
Date: Wed, 20 Jul 2016 10:55:30 GMT
Etag: "547fa7e369ef56031dd3bff2ace9fc0832eb251a"
Keep-Alive: timeout=5, max=1000
Last-Modified: Tue, 19 Jul 2016 00:59:33 GMT
Server: Apache
Transfer-Encoding: chunked
Vary: Cookie, Accept-Encoding
 
(content)

content 내 추가 리소스를 요청하기 위해 다시 한 번 더 요청합니다.

# 두 번째 요청 - 연결 유지
GET /static/img/header-background.png HTTP/1.1
Host: developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header
 
# 두 번째 요청에 대한 응답
200 OK
Age: 9578461
Cache-Control: public, max-age=315360000
Connection: keep-alive
Content-Length: 3077
Content-Type: image/png
Date: Thu, 31 Mar 2016 13:34:46 GMT
Last-Modified: Wed, 21 Oct 2015 18:27:50 GMT
Server: Apache
 
(image content of 3077 bytes)

keep-alive 를 통해서 연결을 끊지 않고 유지된 연결 속에서 다음 요청을 진행하여 응답을 받습니다.

Connections

커넥션 관리는 HTTP의 주요 주제입니다. 대규모로 커넥션을 열고 유지하는 것은 웹 사이트 혹은 웹 애플리케이션의 성능에 많은 영향을 줍니다.
- HTTP/1.x의 커넥션 관리

HTTP는 클라이언트와 서버 간의 커넥션을 관리하기 위해 주로 TCP를 전송 프로토콜로 사용합니다.

  • HTTP/1.0 커넥션은 기본적으로 영속적이지 않습니다. Connection를 close가 아닌 다른 것으로, 일반적으로 retry-after로 설정하면 영속적으로 동작하게 될 겁니다.
  • HTTP/1.1에서는 기본적으로 영속적이며 헤더도 필요하지 않습니다(그러나 HTTP/1.0으로 동작하는 경우에 대비해서 종종 추가하기도 합니다.).

초기에는 HTTP 커넥션은 단기 연결로, 매 요청마다 새로운 커넥션을 생성하고 응답이 도착한 후 연결을 닫았습니다.

각각의 TCP 연결을 여는 것은 자원을 소비하기 때문에 이러한 단순한 모델은 선천적으로 성능상의 제약을 발생 시킵니다.

몇몇 메시지들은 클라이언트와 서버 사이에서 교환되어야만 하며, 네트워크의 지연과 대역폭은 요청이 전송되어야 할 때마다 성능에 영향을 줍니다.

현대의 웹 페이지들은 필요로 하는 정보를 제공하기 위해 많은 요청(12개 혹은 그 이상)을 필요로 하므로, 이런 초창기 모델(단기 연결)이 비효율적인 것은 자명합니다.

HTTP/1.1에서 두 가지 모델이 추가되었습니다.

  1. Persistent connection : 영속적인 커넥션 모델은 연속적인 요청 사이에 커넥션을 유지하여 새 커넥션을 여는데 필요한 시간을 줄입니다.
  2. HTTP Pipelining: 응답 조차도 기다리지 않고 연속적인 요청을 보내서 네트워크 지연을 더욱 줄입니다.

15년 넘게 진행된 확장

HTTP/1.1의 확장성 덕분에 두번에 걸친 리비전을 통해 이 프로토콜은 15년 넘도록 극도로 안정적으로 유지해왔습니다.

그 중 주요한 것은 다음과 같습니다.

1. HTTPS (SSL)

넷스케이프 커뮤니케이션은 HTTP 토대 위에 추가적인 암호화된 전송 계층인 SSL을 만들어냈습니다.

SSL1.0은 외부로 릴리즈된 적은 없으나, SSL2.0, SSL3.0, SSL3.1은 서버와 클라이언트 간에 교환된 메시지 인증을 암호화하고 보장하여 e-커머스 웹 사이트를 만들어내도록 했습니다.

SSL은 표준 트랙 상에 놓여졌고, 마침내 TLS가 되어 1.3 버전까지 나왔습니다.

현재는 모든 웹 사이트에서 안정성을 제공하기 위해 제공하고 있습니다.

2. REST

2000년에, HTTP 사용에 대한 새로운 패턴이 고안되었습니다. REST(representatianal state transfer). 브라우저나 서버의 갱신없이 데이터 탐색과 수정을 허용하는 API 제공을 가능하게 했습니다.

2005년부터, 웹 페이지에서 사용 가능한 API들이 급격히 늘어나게 되었고 이들 API 중 몇몇은 새로운 특성화된 HTTP 헤더로, 특정한 목적을 위해 HTTP 프로토콜에 확장을 만들어냈습니다.

  • Server-sent events: 서버가 브라우저로 메시지를 푸쉬할 수 있는 기능
  • WebSocket: 기존 HTTP 커넥션을 업그레이드하여 만들 수 있는 새로운 프로토콜

문제점

1. HOL(Head Of Line) Blocking

HOL Blocking이란 같은 큐에 있는 패킷 중 첫 번째 패킷에 의해 지연될 때 발생하는 성능 저하 현상을 말합니다.

HTTP/1.1 Pipelining을 통해 요청 단계에서는 지연 없이 요청이 가능합니다. 그러나 서버에서 응답은 명세에 의해 HOL Blocking을 해소할 순 없습니다.

Pipelining
...A server MUST send its responses to those requests in the same order that the requests were received....
...서버는 반드시 요청 받은 순서와 동일한 순서로 응답을 해야합니다....
- RFC2616#pipelining

이 이유를 포함해서 여러가지 이유로 인해 파이프라이닝은 실패하였고, 모던 브라우저에서 기본적으로 활성화되어 있지 않습니다.

  • 버그가 있는 프록시들이 여전히 많은데, 이들은 웹 개발자들이 쉽게 예상하거나 분석하기 힘든 이상하고 오류가 있는 동작을 야기합니다.
  • 파이프라이닝은 정확히 구현해내기 복잡합니다 ... 파이프라이닝은 대부분의 경우 미미한 수준의 향상만을 가져다 줍니다.
  • 파이프라이닝은 HOL 문제에 영향을 받습니다.

HTTP 파이프라이닝은 더 나은 알고리즘인 멀티플렉싱으로 대체되었는데, 이는 HTTP/2에서 사용됩니다.

TCP HOL Blocking

HTTP HOL Blocking은 위에 설명한대로 HTTP/2에서 해결가능한 범위에 있습니다.
그러나 TCP 레이어에서 나타나는 고질적인 문제로 발생하는 HOL Blocking도 있습니다.
TCP의 경우 두 엔드포인트 사이 네트워크 어딘가에서 하나의 패킷이 빠지거나 없어진다면 없어진 패킷을 재전송하고 목적지를 찾는 동안 전체 TCP 연결이 중단되게 됩니다.
즉, TCP는 "체인"이기 때문에 한 링크가 갑자기 사라지면 그 링크 이후에 와야 하는 모든 것들이 기다려야 한다는 뜻입니다.
HTTP/3(QUIC)은 UDP 상에 구현되어지기 때문에 TCP HOL Blocking에서 벗어날 수 있습니다.
- TCP HOL Blocking

2. 너무 큰 HTTP 헤더

클라이언트가 서버로 보내는 요청에는 매 요청 때마다 많은 값이 중복된 값을 전송하게 되며 이로 인해 전송 당 500~800바이트의 오버헤드가 추가됩니다. 그리고 HTTP 쿠키를 사용할 경우 수 KB가 추가되기도 합니다.

HTTP/2 - 더 나은 성능을 위한 프로토콜

몇 년에 걸쳐, 웹 페이지는 매우 복잡해지고 대규모의 애플리케이션이 되었습니다.

2010년 전반기, Google은 실험적인 SPDY 프로토콜을 구현하여 클라이언트와 서버 간의 데이터 교환을 대체할 수단을 실증하였습니다.

2015년 5월 공식적으로 표준화된 HTTP/2는 큰 성공을 거두었습니다.

인터넷 상에서 전송 오버헤드 감소로 많은 돈을 절약하는 높은 트래픽의 웹 사이트들은 이 프로토콜을 급속히 받아들였습니다.

HTTP/1.1 버전과 다른 몇 가지 근본적인 차이점을 가지고 있습니다.

  • 이진 프로토콜: 텍스트가 아닌 바이너리로 구성할 수 있습니다.
  • 다중화 프로토콜: 병렬 요청이 동일한 커넥션 상에서 이루어질 수 있습니다.
  • 헤더 압축: 중복된 헤더 데이터와 그로부터 발생하는 불필요한 오버헤드를 제거할 수 있습니다.
  • 서버 푸쉬: 서버에서 클라이언트로 필요하게 될 데이터를 미리 채워넣도록 허용합니다.(그러나 사용이 저조하고 효과가 미비한데 비해 코드의 방대하고 복잡성 등 근거로 두어 2020년 11월 크로미움 그룹에서 제거된다고 발표했습니다.)

디자인 및 기술적 목표

HTTP/1.x 는 단순한 구현을 위해 애플리케이션 성능을 희생해야 했습니다.

HTTP/1.x 클라이언트는 동시성을 실현하고 지연 시간을 줄이기 위해 여러 개의 연결을 사용해야 합니다.

또한 HTTP/1.x 는 요청 및 응답 헤더를 압축하지 않으므로 불필요한 네트워크 트래픽이 발생하며, 효과적인 리소스 우선순위 지정을 허용하지 않으므로 기본 TCP 연결을 제대로 사용할 수 없는 등의 제한이 있습니다.

이러한 제한이 치명적이진 않지만, 웹 애플리케이션이 복잡해지고 중요해짐에 따라 웹 개발자와 사용자에게 더 많은 부담을 주었습니다.

HTTP/2는 이러한 이유 때문에 고안되었습니다.

  • Binary Framing Layer: 텍스트가 아닌 바이너리 프레임을 통해 메시지를 전달합니다.
  • Multiplexing: 병렬 수행 시 여러개 연결을 하는 대신 한 연결 내 병렬 요청을 수행합니다.
  • 스트림 우선순위: 프레임이 분할되어 전송되어지기 때문에 우선순위를 정하는 것이 성능 고려사항이 되었습니다.
  • One connection per origin: 멀티플렉싱을 통하기 때문에 여러 개의 TCP 연결은 더 이상 필요없습니다.
  • 헤더 압축: 헤더 전송 크기를 줄여 네트워크 오버헤드를 줄입니다.

Binary Framing Layer

HTTP/2의 모든 성능 향상 중 핵심은 바이너리 프레이밍 계층입니다.

줄바꿈으로 구분되는 일반 텍스트 HTTP/1.x 프로토콜과 달리, 모든 HTTP/2 통신은 더 작은 메시지와 프레임으로 분할되며, 각각은 바이너리 형식으로 인코딩됩니다.

따라서 클라이언트와 서버는 서로를 이해하기 위해 새 바이너리 인코딩 메커니즘을 사용해야 합니다.

HTTP/1.x 클라이언트는 HTTP/2 전용 서버를 이해하지 못하며 그 반대도 마찬가지입니다.

다행히, 필요한 모든 프레이밍 작업을 클라이언트(브라우저)와 서버가 대신 수행해주기 때문에 애플리케이션은 이 모든 변경을 인식하지 않아도 됩니다.

클라이언트와 서버 간에 데이터 교환 방식과 그와 관련된 용어를 익혀보겠습니다.

  • 스트림: 연결 내에서 전달되는 바이트의 양 방향 흐름
  • 프레임: 통신의 최소 단위이며 최소 단위에는 하나의 프레임 헤더가 포함됩니다.
  • 메시지: 요청, 응답에 매핑되는 프레임의 전체 시퀀스 입니다.

이러한 용어의 관계는 다음과 같이 요약됩니다.

  • 모든 통신은 단일 TCP 연결을 통해 수행되며 양방향 스트림 수는 제한이 없습니다.
  • 스트림에는 양방향 메시지 전달에 사용되는 고유 식별자와 우선순위 정보(선택 사항)가 있습니다.
  • 각 메시지는 하나의 논리적 HTTP 메시지이며 하나 이상의 프레임으로 구성됩니다.
  • 각 프레임의 헤더에 삽입된 스트림 식별자를 통해 이 프레임을 다시 조립할 수 있습니다.

Multiplexing

HTTP/1.x에서 발생하는 문제인 HOL Blocking을 해결할 수 있으며, 여러 개의 연결 없이도 요청 및 응답의 병렬 처리를 지원합니다.

HTTP/1.x에서는 병렬 요청을 수행하려는 경우, 여러 TCP 연결이 사용되어야 합니다. 이 동작은 최대 연결 제한 수 등 제한 사항들도 있을뿐 더러 HOL Blocking과 TCP 연결의 비효율적인 사용을 초래한다는 점입니다.

HTTP/2에서는 단일 연결 내 프레임을 인터리빙(끼워넣기)한 다음, 다른 쪽에서 다시 조립하도록 허용하여 요청, 응답 다중화를 지원합니다.

  • 여러 요청을 Blocking 없이 병렬로 전달 할 수 있습니다.
  • 여러 응답을 Blocking 없이 병렬로 전달 할 수 있습니다.
  • 단일 연결 내에 여러 요청, 응답을 병렬로 전달 할 수 있습니다.
  • HTTP/1.x의 최적화 잔재인 concatenated files, image sprites, domain sharding 을 제거합니다.
  • 불필요한 네트워크 오버헤드를 제거하고 네트워크 용량의 활용도를 개선하여 페이지 로드 시간을 줄입니다.

스트림 우선순위

메시지가 프레임으로 분할될 수 있고 다중화될 수 있음에 따라 전달되는 순서가 중요한 성능 고려사항이 되었습니다.

HTTP/2 표준에서는 각 스트림이 가중치와 종속성을 갖도록 허용합니다.

  • 각 스트림에는 1~256 사이의 정수 가중치가 할당될 수 있습니다.
  • 각 스트림에는 다른 스트림에 대한 명시적 종속성이 부여될 수 있습니다.

스트림의 종속성 및 가중치 조합을 이용하여 클라이언트가 '우선순위 지정 트리'를 구성하고 통신할 수 있습니다.

이 트리는 클라이언트가 선호하는 응답 수신 방식을 나타냅니다. 그러면 서버가 이 정보를 사용하여 CPU, 메모리, 기타 리소스의 할당을 제어하여 스트림 처리 우선순위를 지정합니다.

응답이 있을 경우, 서버는 우선순위가 높은 응답이 클라이언트에 최적으로 전달되도록 대역폭을 할당합니다.

더 자세한 내용은 여기서 확인하시면 됩니다.

One connection per origin

TCP 레이어는 수명이 길고 대량 데이터 전송에 최적화되어 있습니다.

그에 비해 HTTP 전송은 수명이 짧고 폭발적인 데이터 전송에 적합합니다.

바이너리 프레이밍 매커니즘에 의해 여러 개의 TCP 연결이 더 이상 HTTP/2에 필요 없습니다.

각 스트림은 여러 프레임으로 분할되며 각 프레임이 인터리빙(끼워넣기)되고 우선순위가 지정될 수 있습니다.

따라서, 모든 HTTP/2 연결은 영구적이고 one connection per origin만 필요하며 이 경우 성능상의 수 많은 이점이 있습니다.

HTTP/2에서는 동일한 연결을 재사용하여 TCP 연결이 더 효율적으로 사용할 수 있으며 프로토콜 오버헤드를 대폭 줄일 수 있습니다.(TCP는 연결 할 때마다 3-way, 4-way handshake등이 일어나므로)

이로 인해 전체 연결 경로(클라이언트, 중개 장치, 서버)에서 메모리와 처리량이 줄어듭니다. 그로 인해 전체 비용이 절감되고 네트워크 활용도와 용량이 개선됩니다.

연결 수가 적다는 것은 HTTPS 배포 성능을 개선하는데도 특히 중요합니다.

값 비싼 TLS 핸드세이크가 줄어들고, 세션 재사용이 더 향상되며 필요한 클라이언트 및 서버 리소스가 감소합니다.

서버 푸쉬

2020년 11월 chromium.org는 server push와 관련된 기능을 주요 엔진에서 제거하기로 발표했습니다.
- Intent to Remove: HTTP/2 and gQUIC server push

서버 푸쉬는 서버가 클라이언트로 기존 요청에 대한 응답 뿐만아니라 클라이언트가 명시적으로 요청하지 않아도 서버가 추가적인 리소스를 클라이언트에 푸시할 수 있는 기능입니다.(js, css 위주)

cdn 캐싱, 클라이언트 캐싱, 재사용성 등에 효과가 좋습니다.(라고 예상되었으나 HTTP/2 전체 사용범위 중 0.05% 정도만 이용하고 있었습니다.)

지난 28일 동안 크롬에 의해 만들어진 HTTP/2연결 의 99.95%가 pushed stream을 수신하지 않았으며 HTTP/2연결의 99.97%가 요청에 매치되는 pushed stream을 받은 적이 없습니다. 이 숫자는 2019년 6월 정확히 동일합니다.
...
Server push는 사용하기 꽤 어렵습니다.
...
push를 지원하는 Chromium과 관련된 상당한 코드 복잡성이 있습니다.
- Intent to Remove: HTTP/2 and gQUIC server push

헤더 압축

HTTP/1.x의 경우 메타데이터는 항상 일반 텍스트로 전송되고, 전송당 500~800바이트의 오버헤드가 추가되며, HTTP 쿠키를 사용할 경우 수 KB가 추가되기도 합니다.

HTTP/2는 기존 HTTP/1.x의 헤더의 오버헤드를 줄이고 성능을 개선하기 위해 HPACK 압축 형식을 사용하여 요청, 응답 헤더 메타데이터를 압축합니다.

이 압축 형식에서는 단순하지만 강력한 두 가지 기술을 사용합니다.

  1. 전송되는 헤더 필드를 정적 Huffman 코드로 인코딩합니다.(개별 전송 크기를 줄임)
  2. 클라이언트와 서버가 동일 헤더 목록에 대해 색인 목록을 관리합니다.(전송 대상을 줄임)
  • 각 헤더 메타데이터는 정적 Huffman 코드로 압축하여 전송됩니다.
  • Request #1를 요청, 응답하였을 때 헤더에 대한 색인 목록을 생성합니다.
  • Request #2 요청, 응답 시 기존과 변경된 :path에 대해서만 전송합니다.

HTTP/3 - QUIC

HTTP/3는 HTTP/2를 이은 차기 주요 버전이자 HTTP의 3번째 프로토콜입니다. 주요 변경점은 TCP대신 QUIC이라 불리는 새로운 UDP 프로토콜을 사용합니다.
- http3-mdn

구글이 개발한 QUIC 프로토콜을 사용하여 기존의 HOC Blocking(TCP) 문제를 해결하는 것이 목적입니다. TCP가 아닌 UDP 상에서의 프로토콜 입니다.

2020년 10월 기준으로 HTTP/3는 초안이며 여러 버전이 존재합니다. W3Techs에 따르면 10,000,000개 웹사이트 중 8%가 지원한다고 합니다.

HTTP/3, QUIC을 구현하는 것은 쉽지 않고 프로토콜은 오늘날 까지고 계속 진화하며 변하고 있습니다.

QUIC

Quick UDP Internet Connection

UDP 상에 구현된 실험적인 다중 전송 프로토콜로 TCP 및 웹 애플리케이션 전송을 개선하기 위한 방법을 위해 Google에서 실험적으로 개발하였습니다.

HTTP/3 vs HTTP/2

이 두 프로토콜은 사실상 같은 기능을 제공합니다. 단지, HTTP/3는 QUIC 사용에 따른 차이점만 있습니다.

유사점

  • 두 프로토콜은 스트림을 제공합니다.
  • 두 프로토콜은 서버 푸시를 지원합니다.
  • 두 프로토콜은 헤더 압축을 제공합니다. QPACK과 HPACK은 설계상 비슷합니다.
  • 두 프로토콜은 스트림을 이용해서 하나의 연결을 통해 멀티플랙싱을 제공합니다.
  • 두 프로토콜은 스트림에 우선순위를 정할 수 있습니다.

차이점

  • HTTP/3는 QUIC 덕에 TCP + TLS보다 훨씬 더 빠른 핸드쉐이크를 제공합니다.(1-RTT or 0-RTT) 1-rtt
  • HTTP/3에는 안전하지 않거나 암호화되지 않은 버전이 없습니다. 연결 설정 시에 필요한 정보와 함께 데이터도 같이 보내기 때문입니다.(HTTP/2를 가지고도 드물기는 하지만 HTTPS 없이 구현할 수도 있습니다. HTTP/3는 원칙적으로 불가능합니다.)

마치며

HTTP에 대해 깊이 알아본 흥미로운 경험이었습니다. 많은 부분을 모르거나 간과했을 수 있지만...

무언가를 배워서 어딘가에 도움이 되면 좋겠지만, 그렇지 않더라도 HTTP에 대해 알아보는 시간이 흥미로웠으면 되었습니다.

reference

마지막 업데이트

3/26/2023


Avatar

JHSeo

배우는 것을 좋아하고 관심이 많은 웹 엔지니어 입니다. 느리더라도 꾸준하게 성장하려고 노력하는 개발자입니다.