HTTP/3, 제대로 이해하기

2023. 1. 1. 23:58BACKEND

반응형

해당 포스팅은 HTTP/3의 구조와 특징에 대해 이전 HTTP 프로토콜과 비교하여 이해하는 것을 목표로 합니다.

 

2022년 6월, HTTP의 세 번째 버전인 HTTP/3가 IETF(Internet Engineering Task Force) 표준으로 채택되었습니다. 새로운 표준에 어떤 특징이 있는지, 웹 상에 어떤 변화가 있을지 알아볼 필요가 있어 보이는데요. 그래서 해당 포스팅에서 HTTP/3의 등장 이유와 그 특징에 대해 알아보겠습니다. 물론, 표준으로 채택된 후 바로 웹 상에 적용되지는 않겠지만, 이를 대비해두고 준비해야할 필요는 있습니다.

 

 

HTTP

HTTP는 HyperText Transfer Protocol의 약자로, 링크를 통해 다른 문서로 연결될 수 있는 문서를 전송하는 규격이 정해진 규칙 체계입니다. 웹이 생기고 오랜 시간이 지난 지금, 웹 상에는 많은 양의 리소스 뿐만 아니라 큰 용량의 리소스들이 클라이언트와 서버의 통신으로 전송되고 있습니다. 큰 용량의 많은 자원들이 오가면서 네트워크의 복잡도는 높아지지만, 반대로 사용자들은 더 빠른 웹 성능을 요구합니다. 이런 변화와 요구에 상응하도록, 네트워크 상의 자원 전송하는 방식은 최적화 되어야 합니다.

 

HTTP는 이러한 전송 방식에 대한 표준이며, 꾸준한 최적화와 업그레이드로 시키는 이유입니다. 그럼 지금부터 HTTP/3까지 도달하기 까지의 HTTP의 역사를 짧게 훑어보도록 하겠습니다.

 

 

 

HTTP/0.9

HTTP/0.9는 One-Line Protocol로 불리며, 이 초기 HTTP는 버전 번호가 없는 상태로 발표되었습니다. HTTP는 요청이 단일 라인으로 구성되며 GET 메서드만이 존재했습니다. 서버에 연결되면 프로토콜, 서버, 포트는 불필요해지기 때문에 아래와 같이 아주 단순한 형태를 띄었습니다.

 

[Request]
GET /mypage.html

[Response]
<HTML>A very simple HTML page</HTML>

 

이 때는 Header도 없었는데, HTML만이 전송될 수 있었음을 의미합니다. 또, 요청에 대한 상태나 오류 코드도 없었습니다.

 

 

HTTP/1.0

HTTP1.0을 일단 해보자는 'try-and-see' 방법으로 시작됐습니다. 서버와 브러우저에 기능을 추가했고, 상호운용성 문제가 일반적이었습니다. 1996년에 이러한 문제를 해결하고자 일반적인 관례들을 적은 문서를 발행했고, 이것을 RFC 1945 라고 하며 HTTP/1.0로 정의했습니다. HTTP/1.0의 특징은 아래와 같습니다.

 

✔️ 버전 정보를 명시하기 시작

✔️ 응답에 Status Code 추가: 브라우저가 요청에 대한 성공과 실패를 구별

✔️ 요청과 응답에 헤더 추가: 메타데이터를 허용하고, Content-Type 명시로 다양한 타입의 문서도 전달 가능

 

[Request]
GET /mypage.html HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)

[Response]
200 OK
Date: Tue, 15 Nov 1994 08:12:31 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/html
<HTML>
    A very simple HTML page
    <img src="/myimage.gif"/>
</HTML>

 

 

HTTP/1.1

The Standard Protocol

 

HTTP/1.1는 HTTP/1.0이 나온지 몇 달 안돼서 1997년 초에 공개되었습니다. HTTP/1.0에서의 모호함을 없애고 명확한 정의를 내리게 됩니다. 많은 내용들이 담기고 특히 헤더가 무거워진 형태의 메세지를 볼 수 있습니다. HTTP/1.1은 확장성이 뛰어나서 1999년부터 새로운 RFC 문서 시리즈와 HTTP/2 릴리즈를 예견하는 상황에도 15년 동안 확장되고 안정성을 유지해왔으며, 변화와 확장이 일어났습니다.

 

HTTPS

TCP/IP 스택을 통해 HTTP를 전송하는 대신, 암호화된 전송 계층인 SSL을 만들었습니다. 웹에서 주소록이나 이메일, 사용자의 위치 정보나 개인정보 등에 접근하면서 점점 보안의 중요성이 대두되면서 생겨났으며, SSL은 TLS로 발전해왔습니다. 현재는 SSL이 아닌 TLS을 사용하지만, 보편적으로 SSL이라고 부르기 때문에 SSL/TLS을 혼용하여 부른다고 합니다.

 

RESTful API

2000년에 HTTP 사용에 대한 새로운 사용 패턴으로 REST가 등장했습니다. 표준 규격이 없다는 단점이 있지만, 2010년 부터는 매우 일반적으로 사용되었습니다.

 

Pipelining

이전 요청의 응답을 완전히 전송되기 전에 다음 요청을 가능하게 해서 통신 대기 시간을 납춥니다.

 

 

왼쪽은 HTTP/1.1 Baseline 통신 규약이고, 오른쪽이 바로 Pipelining 기능이 도입된 HTTP/1.1 통신 과정입니다. HTTP/1.1의 동작은 기본적으로 Connection 한 개당 하나의 요청을 처리하도록 설계되어 있습니다. 동시 전송이 불가능하고 요청과 응답이 순차적으로 이뤄집니다. 또, HTML 문서 안에 포함된 다수의 리소스 (Images, CSS, Script)를 처리하려면 요청할 리소스 개수에 비례해서 Latency(대기 시간)는 길어지게 됩니다.

 

 

 

HTTP/2

HTTP/2는 HTTP/1 의 확장으로 기존의 HTTP/1과의 호환성을 유지하며 성능에 초점을 맞춘 프로토콜입니다. HTTP/2는 Google이 제작한 프로토콜인 SPDY를 기반으로 합니다. 웹 환경이 계속해서 바뀌면서 (리소스 증가, 다수의 도메인, 동적 웹 서비스, 보안의 중요성 대두 등) 구글은 전송 지연latency 문제의 해결을 집중하며 HTTP를 고속화한 새로운 프로토콜인 SPDY를 구현했으며, Google이 자신들의 'Make the Web Faster' 노력의 하나로 제안한 새로운 프로토콜입니다.

 

Multiplexed Streams

HTTP/2는 하나의 TCP 연결을 통해 여러 데이터 요청을 병렬로 전송할 수 있습니다. HTTP/2는 Multiplexed Streams를 이용하여 Connection 한 개로 동시에 여러 개의 메시지를 주고 받을 수 있으며 응답은 순서에 상관없이 Stream으로 주고 받습니다. 이로 인해 Head-of-line Blocking 의 문제를 해결할 수 있었습니다. Head-of-line Blocking은 순차적으로 수신 받는 패킷 중 하나의 패킷 정보가 도달하지 못했을 때 그 이후의 모든 스트림을 받지 않는다는 이전 HTTP 프로토콜 상의 문제입니다.

 

 

 RTT 시간이 줄어들어 별도의 최적화 과정이나 도메인 샤딩없이 웹 사이트 로드 속도가 빨라집니다. HTTP/1.1의 Connection Keep-Alive, Pipelining의 개선된 것을 알 수 있습니다.

 

Header Compression

HTTP/2는 중복 헤더 프레임을 압축해서 전송합니다. 모바일과 같이 업로드 대역폭이 상대적으로 작은 경우에는 이런 HTTP 헤더 압축 방법이 특히 유용한데, 오늘날의 HTTP 헤더는 평균 2KB 가량이고, 점점 더 커지는 추세이기 때문에 HTTP 헤더 압축의 가치는 앞으로는 더 커질 것이라고 합니다.

 

Binary protocol

텍스트 프로토콜에서 바이너리 프로토콜로 변화했습니다. 기존 HTTP/1에서 사용된 frame의 복잡성을 편리하게 해주고, 텍스트와 공백들이 섞여 혼동이 발생하던 명령들보다 명령어를 단순하게 구현할 수 있습니다. HTTP/2 구현을 사용하는 브라우저는 네트워크를 통해 전송하기 전에 동일한 텍스트 명령을 바이너리로 변환합니다.

 

Server Push

서버는 요청되지 않았지만 향후 요청에서 예상되는 추가 정보를 클라이언트에 전송할 수 있습니다. 예를 들어, 클라이언트가 리소스 X에 대해 요청하고 리소스 Y가 요청된  X 파일에서 참조되는 경우, 서버는 클라이언트 요청을 기다리는 대신 X와 함께 Y를 푸시하도록 선택할 수 있습니다.

 

Stream Prioritization

클라이언트가 선호하는 응답 수신 방식을 지정해서 응답을 받을 수 있습니다. 문서 내에 CSS 파일 1개와 이미지 파일 2개가 존재하고 이를 클라이언트가 요청한다고 가정해봅시다. 이미지 파일보다 CSS 파일의 수신이 늦어진다면 브라우저 렌더링에 문제가 생기게 될 수 있는데, HTTP/2에서는 이러한 상황을 고려하여 리소스 간의 의존관계에 따른 우선순위를 설정하여 리소스 로드 문제를 해결할 수 있습니다.

 

 

HTTP/3

HTTP/2는 2015년에 등장했습니다. 그런데 얼마 지나지 않은 2022년 6월이 되고 HTTP/3가 등장했습니다. 표준 프로토콜의 업그레이드가 굉장히 빠른 속도로 진행되었는데요. 어떤 변화가 있었길래 이러한 변화가 있었는지 알아보도록 하겠습니다.

 

 

TCP의 문제점 중 하나는 클라이언트와 서버 간에 세션을 설정하기 전에 보안 세션을 확인으로 TLS Handshake가 필요하다는 것입니다. 위 그림 중 HTTP/2인 좌측 구조를 확인해 보면, TCP인 HTTP/2 아래에 TLS가 존재하며, 이 구조로 인해 부가적인 Handshake가 필요합니다. 결론적으로, 위의 그림과 같이 HTTP/3는 새로운 프로토콜 QUIC(Quick UDP Internet Connections)을 채택하여 이 문제를 해결합니다. HTTP/2와 HTTP/3 프로토콜의 구조를 확인할 수 있으며 TCP와 TLS의 위치와 구조가 어떻게 다른지 보여줍니다. 

 

 

QUIC

HTTP/3는 QUIC(Quick UDP Internet Connections) 프로토콜을 기반으로 하며, QUIC은 새로운 UDP 위에서 Multiplexing 전송하는 새로운 프로토콜입니다. QUIC은 기존 방식의 HTTP/2의 단점을 수정함과 동시에 이전에 사용되던 장점들 또한 구현하였습니다.

 

Multiplexing without HOL Blocking

HTTP/2의 강점 중 하나인 멀티플렉싱을 구현합니다. QUIC은 새로운 Multiplexing 전송을 사용하는데, 여러개의 요청을 동일한 HTTP Connection 상에서 주고 받을 수 있다는 강점을 지닙니다. 더 이상 속도가 늦은 응답을 기다리지 않아도 되며, 순서와 상관없는 응답을 받아들일 수 있습니다. Head-Of-Line blocking을 해결하여 빠른 속도의 연결을 가능하게 해주는 특징입니다.

위에서도 언급했지만 다시 설명하자면, Head-of-line Blocking은 순차적으로 수신 받는 패킷 중 하나의 패킷 정보가 도달하지 못했을 때 그 이후의 모든 스트림을 받지 않는다는 이전 HTTP 프로토콜 상의 문제입니다.

 

 

UDP 기반의 프로토콜

QUIC은 UDP 위에 빌드됩니다. 하지만, TCP의 거의 모든 특징들을 재구현함으로써 완전히 안정적인 형태를 띕니다. QUIC은 패킷의 수신 여부를 확인하고 중간에 잃어버린 패킷을 위해 재전송하는데, 이를 위해 아주 복잡한 handshake를 수행하며 연결합니다.

게다가, 이미 모든 인터넷 상에 전송 계층으로 알려져 있는 UDP를 채택함으로써, QUIC을 사용하기 위해 별도의 업데이트나 설치 과정이 필요 없다는 큰 이점을 지닙니다.

 

 

빠른 연결 :: Faster connection establishment

QUIC는 TLS 버전을 위해 암호화와 handshake를 동시에 수행할 수 있도록 합니다. TCP와 TLS를 함께 사용하며 더 많은 handshake를 필요로하는 HTTP/2 와 비교되어 굉장히 빠른 handshake를 실행할 수 있습니다.

 

https://www.section.io/engineering-education/http3-vs-http2/

 

 

Zero round-trip time (0-RTT)

한 번 HTTP 연결이 이루어지고 나면, 클라이언트는 더 이상 handshake를 통해 통신 방법을 확인하려 서로를 확인하는 프로세스를 진행하지 않습니다.

 

https://www.toptal.com/web/performance-working-with-http-3

 

사실, 이전부터 이론 상에서는 가능하지만, 애초에 초기 설계가 TLS가 위에 있을 수도 없을 수도 있는 TCP를 사용해야 하는 방식이었기 때문에 한계가 있었습니다. 지속적인 확인이 필요했기 때문이죠. 하지만, QUIC은 초기 설계를 이에 해당하는 개념으로 구현했기 때문에 원하는 대로 빠르게 동작하는 것이 가능한 것입니다.

 

 

항상 암호화된 전송

HTTP/3는 안전하고 암호화된 방식으로만 수행될 수 있습니다. HTTP/2에서 두드러지게 업그레이드된 내용 중 하나로, handshake에 대한 QUIC의 새로운 접근 방식으로 기본적인 암호화를 제공하기 때문에 공격을 완화하는 데 도움이 될 것으로 예상됩니다.

 

 

 

Implementation

HTTP/3는 몇몇의 서비스에서 지원을 하고 있습니다. Caddy, Nginx, AWS Cloudflare 가 대표적입니다. 아래의 표는 각 언어 별 구현 레포지토리입니다. 


Language Implementation
Python Aioquic
Go Quic-go
Rust Quiche (Cloudflare), Quinn, Neqo (Mozilla), s2n-quic (AWS)
C and C++ mvfst (Facebook), msquic, (Microsoft), lsquic (Litespeed), picoquic, quicly (Fastly)

 

코드를 분석하는 것은 좋겠지만, 사실 지금 단계에서는 조금 이를 수 있을 텐데요. 아시다시피, 모두 정기적으로 변경되는 내용이나 코드가 많을 예정이기 때문입니다.

 

반응형

Backend Software Engineer

Gyeongsun Park