QUIC 프로토콜
차세대 transport 계층 네트워크 프로토콜 QUIC에 대해 알아보자.
QUIC 프로토콜 개요
QUIC은 Google에서 2012년 개발한 범용 transport 계층 프로토콜이다.
현재 YouTube 등 구글이 제공하는 모든 서비스 및 Chrome 브라우저에 적용되어 있으며, Microsoft Edge와 Firefox도 지원한다.
기존 TCP의 단점(특히 레이턴시)을 보완하고 TCP를 사용하는 connection-oriented 웹 어플리케이션들에서 TCP의 기능을 대체하기 위해 만들어졌다. QUIC은 이 목적을 UDP 기반의 multiplexed connection establishment를 통해 달성한다. TCP를 대체하기 위해 설계되었기 때문에, TCP/2라는 별명으로 불리기도 한다.
Multiplexed Connection이란?
여러 개의 데이터 스트림을 Multiplexing하여 하나의 Connection을 통해 동시에 전송하는 것이다. 이때, 각 데이터 스트림은 고유한 ID를 갖는다.
TCP와 달리 데이터 스트림이 분리되어 전송되기 때문에 한 스트림에서 발생한 패킷 손실이 다른 스트림에 영향을 미치지 않는다고 한다. 또한, 각각의 스트림은 독립적인 수준의 버퍼링을 가지고 있어서, 한 스트림에서 발생한 지연이 다른 스트림에 영향을 미치지 않고, 전체적인 데이터 전송 속도를 향상시킨다고 한다.
이러한 특징은 HTTP/3와 같은 응용 계층 프로토콜에서 이점을 제공한다. 예를 들어, HTTP/3에서는 하나의 connection을 통해 여러 개의 요청과 응답을 처리할 수 있으므로 이를 통해 웹 페이지의 로딩 속도를 향상시킬 수 있다. 그리고 HTTP/3에서는 한 connection에서 발생한 패킷 손실이 다른 connection에 영향을 미치지 않으므로 전체적인 데이터 전송 속도와 신뢰성이 향상된다고 한다.
QUIC의 두 번째 goal은 connection 및 transport latency의 감소, 그리고 congestion(데이터의 양과 네트워크 내 링크 또는 노드의 처리력 차이로 인한 병목 현상)을 막기 위한 양방향 bandwidth estimation이라고 한다.
QUIC은 congestion control이 커널 영역이 아닌 유저 영역에서 수행되도록 한다고 하는데 이는 알고리즘의 개선이 더욱 빠르게 이루어지는 효과가 있다고 한다.
그리고, 에러가 예상되는 경우 forward error correction(FEC)를 통해 더욱 성능 향상을 꾀할 수 있다고 한다. 이 프로토콜은 protocol ossification(경직화)를 막기 위해 설계되어서, 심하게 경직된 TCP와는 대비된다고 한다.
배경
TCP는 한 connection에서 에러 발생이 감지되면 모든 작업을 중지하고 해결될 때까지 기다린다. 여러 데이터 스트림을 보내기 위해 하나의 connection이 사용될 경우, 하나의 스트림에서 에러가 발생하면 모든 스트림이 차단된다. 예를 들어, 웹페이지의 favicon 이미지를 다운로드 받는 동안 에러가 발생하면 그 페이지의 나머지 부분 전체가 로딩을 중단하고 문제 해결을 위해 대기한다. 이러한 현상을 head-of-line blocking이라고 한다.
TCP 위에 TLS 암호화와 같은 추가적인 시스템을 얹으려고 하면, 각각의 시스템은 자신만의 handshake 과정이 따로 필요하게 된다. 이는 결국 원거리 통신의 latency로 인해 전체 transmission의 심각한 오버헤드로 작용할 수 있다.
특징
TCP + TLS1.2 와 비교한 QUIC의 handshake 과정
QUIC은 TCP connection과 거의 동등한 기능을 수행하는 것이 목적이다. 단, 이에 더해 크게 감소된 latency를 달성해야 한다.
이 목적은 HTTP 트래픽의 행위에 대한 이해에 의존하는 두 가지 변화를 통해 주로 달성된다.
첫 번째 변화는 connection setup 과정에서의 오버헤드를 크게 줄이는 것이다. 대부분의 HTTP connection이 TLS를 요구하므로, QUIC은 setup key의 교환과 지원되는 프로토콜(TLS 1.3)을 초기 handshake 과정에 포함시켰다.
클라이언트가 connection을 열 때, 이때 이미 TLS Hello를 같이 보낸다. 그리고, response 패킷에는 암호화를 위해 추후 패킷들에 필요한 데이터가 포함되어 날아 온다. 이는 TCP connection을 열고 나서 추가적으로 추가 패킷들을 통해 보안 프로토콜을 negotiation 해야 할 필요를 없앤다. 다른 프로토콜들도 위와 같은 방식으로 서비스 가능하다. 여러 개의 단계들을 하나의 request-response로 합치는 것이다. 이 데이터는 초기 setup에서 뒤따르는 request들 및 분리된 connection을 통해서 negotiated되어야 할 추후의 request들에 모두 사용될 수 있다.
TCP가 아닌 UDP를 베이스로 사용하므로, 손실 회복을 지원하지 않는다. 그 대신, 각 QUIC 스트림이 각각 flow control 되며, 손실된 데이터는 UDP가 아닌 QUIC단에서 재전송된다. 이는 오류 발생 시에도 프로토콜 스택이 다른 스트림을 계속 독립적으로 서비스할 수 있음을 뜻한다. 이는 에러가 많은 링크들의 성능을 크게 향상하는 효과가 있다. TCP는 에러 수정 시 다른 데이터들이 막히거나 flushed 되는 반면 QUIC은 한 multiplexed stream이 수리될 때 다른 데이터는 자유롭게 처리될 수가 있다.
그밖에도 latency와 throughput을 향상시킬 수 있는 다른 기법들이 적용되어 있으며, 네트워크 전환 시의 효율적인 대응도 구현되어 있다. 네트워크 전환 시에도 QUIC의 Connection ID는 불변으로 남아있어 한번 형성된 Connection을 계속 이용할 수 있다.
QUIC 0-RTT
두 end point가 최근에 통신 이력이 있었다면, 알려진 parameter들을 가지고, 클라이언트가 서버에 보내는 첫 패킷으로 바로 Application 단의 requests (HTTP/3 등)를 보낼 수 있다.