[Network] Extra. 버전에 따른 HTTP

KYJ의 Tech Velog·2023년 4월 26일
0

Network

목록 보기
14/21
post-thumbnail

HTTP Version

HTTP/1.0 -> HTTP/1.1

HTTP/1.0은 요청마다 연결/해제의 과정이 발생하였습니다. 이로 인해 오버헤드가 발생하였고 시간의 지연이 발생했습니다. 비연결성을 유지해서 더 많은 연결을 할 수 있게 하기 위함이었습니다.

HTTP/1.1에서는 2개의 연결 방식을 추가해서 이를 개선하고자 하였습니다. Persistent connection 모델과 더 발전한 HTTP Pipelining 입니다.

  • Persistent connection
    연결의 지속 시간을 설정하여 지속 시간 동안에는 연결/해제 과정이 발생하지 않도록 하였습니다. 하지만 결국 요청 후에 응답을 기다려야하고 이 대기 시간에는 또 아무것도 할 수 없었습니다.
  • Pipelining
    클라이언트에서 요청을 응답에 상관없이 보내고 서버에서 응답을 요청이 들어온 순서대로 보냅니다. 이 때 클라이언트에서 응답의 순서가 잘못되거나 누락되었다면 그 요청을 다시 보냅니다.

하지만 Pipelining도 HOL(Head Of Line) Blocking 문제가 있습니다. 클라이언트에서 A, B 요청을 보냈습니다. 서버에서 A, B를 처리하는 데에 각각 100초, 10초가 소요된다고 가정하겠습니다. 클라이언트에서는 두 요청이 다 처리되었지만 서버에서 A가 수행되는 시간동안 B에 대한 응답은 계속 blocking 됩니다.

헤더 구조의 중복 문제도 있습니다. 연속된 요청의 경우 헤더가 같은 값인 경우가 많음에도 불구하고 그대로 전송합니다. 이로 인해 데이터가 불필요하게 커지게 됩니다.


HTTP/1.1 -> HTTP/2

Multiplexed Streams

하나의 TCP 연결을 통해 여러 데이터 요청을 병렬로 전송할 수 있습니다. 여러 개의 메시지를 주고 받을 수 있으며 응답은 순서에 상관없이 스트림으로 주고 받습니다. HTTP 메시지를 바이너리 형태의 프레임으로 나누고 이를 전송합니다. 프레임의 헤더에 삽입된 스트림 식별자를 통해 수신 측에서 다리 조립하여 메시지를 확인합니다. RTT(Round Tip Time)가 줄어들어 웹 사이트 로드 속도가 빨라집니다.

Header Compression

중복된 헤더 프레임을 압축해서 전송합니다. 클라이언트와 서버에서 모두 이전 요청에 사용된 헤더 목록을 관리합니다. HPACK이라는 알고리즘을 사용합니다. HPACK은 서버로 전송되기 전에 각 헤더의 개별 값을 압축한 당므 이전에 전송된 헤더 값 목록에서 인코딩된 정보를 조회하여 전체 헤더 정보를 재구성합니다.

Binary Framing


텍스트 형식으로 전달되던 메시지는 프레임 단위로 나누어지고 바이너리 형식으로 인코딩 됩니다. 바이너리는 컴퓨터가 더 이해하기 쉽기 때문에 파싱, 전송 속도가 빨라졌습니다.

Server Push

서버는 요청되지 않았지만 향후 요청에서 예상되는 추가 정보를 클라이언트에 전송할 수 있습니다.

Stream Prioritization

클라이언트가 선호하는 응답 수신 방식을 지정해서 응답을 받을 수 있습니다. 상황에 따라 리소스 간의 의존관계에 따른 우선순위를 설정해서 리소스 로드 문제를 해결할 수 있습니다.


HTTP/3

TCP로 통신하는 이전 버전과 달리 UDP 기반의 QUIC 프로토콜을 사용하여 통신합니다. TCP는 신뢰성이 높지만 느립니다. 핸드쉐이크 과정으로 인해 느려지는 문제와 HOL Blocking 같은 문제도 가지고 있습니다. QUIC 프로토콜은 TCP의 핸드쉐이크 과정을 최적하는 것에 초점을 맞추어 설계되었고 UDP를 사용하여 이를 실현하였습니다.

UDP는 TCP보다 신뢰성이 없는 대신 빠르다라는 말은 맞긴 합니다. 하지만 반은 맞고 반은 틀립니다. UPD는 데이터 전송을 제외한 어떤 기능도 정의되어 있지 않은 프로토콜입니다. 다시 말해 사용자가 커스터마이징할 수 있는 여지가 많다는 이야기입니다. 기존 UDP를 사용하더라도 TCP가 가지고 있던 기능을 전부 구현할 수 있습니다. TCP는 커스터마이징할 수 있는 자리가 거의 남아있지 않습니다. 따라서 TCP 자체를 발전시키는 것은 어려운 일입니다.

Connection

QUIC 프로토콜은 TCP를 사용하지 않기 때문에 핸드 쉐이크 과정을 거치지 않아도 됩니다. 따라서,첫 연결 시 1.5 RTT가 필요한 TCP와 다르게 1 RTT만 소요됩니다. QUIC은 연결 설정에 필요한 정보와 함께 데이터도 전송해버립니다.

Flow Control

QUIC은 헤더의 별도의 패킷 번호 공간을 부여합니다. 패킷의 전송 순서 자체만을 나타내며 재전송 시에도 변하기 때문에 패킷의 전송 순서를 명확하게 파악할 수 있습니다. 따라서 다음과 같은 경우를 명확하게 해줍니다.

패킷 전송 -> 타임 아웃 -> 패킷 재전송 -> ACK 받음!
(근데 이거 첫 번째로 보낸 패킷의 ACK야? 두 번째로 보낸 패킷의 ACK야?)

이를 통해 패킷 손실을 감지하는 시간도 줄였습니다.

Multiplexing

멀티플렉싱을 지원해서 HOL Blocking을 방지하였습니다. 여러 개의 스트림을 사용하면 특정 스트림의 패킷이 손실되더라도 해당 스트림에만 영향을 미치고 나머지 스트림은 정상적으로 사용이 가능합니다. 이는 HTTP/2도 동일하게 지원하고 있습니다.

Client IP

TCP의 IP 주소와 포트로 연결을 식별하기 때문에 클라이언트의 IP가 변경되면 연결이 끊어집니다. 다시 연결을 생성하기 위해 다시 핸드쉐이크 과정을 거쳐야해서 레이턴시가 발생하게 됩니다. 최근에는 모바일로 인터넷을 사용하는 경우가 많기 때문에 Wi-fi에서 셀룰러 전환 또는 반대의 경우, Wi-fi가 변경되는 경우와 같이 클라이언트의 IP가 변경되는 일이 잦기 때문이 이 문제가 두드러집니다.

QUIC은 Connection ID를 사용해서 연결을 생성합니다. 이 ID는 랜덤한 값일 뿐 IP와는 전혀 무관하기 때문에 IP 변경의 영향을 받지 않습니다.

0개의 댓글