[2022-03-08] - HTTP 3.0

Onni·2022년 3월 8일
0

✅ TCP

TCP는 신뢰성이 높고 느리다, UDP는 신뢰성이 낮고 빠르다

✔ 3 Way Handshake


이 통신 과정을 거치고 나면 클라이언트와 서버는 신뢰성 있는 TCP 연결을 생성할 수 있고, 이때 총 3회의 통신을 하기 때문에 3 Way Handshake라고 하는 것이다.

새로운 TCP 연결을 생성하고자 할 때 클라이언트가 서버에게 랜덤한 시퀀스 번호를 전송함으로써 3 Way Handshake가 시작된다. 이때 생성된 시퀀스 번호는 이후 송신 측이 전송한 패킷을 수신 측이 재조립할때 패킷의 조립 순서를 알려주는 역할을 한다.

이때 클라이언트와 서버는 상대방이 보내준 seq(시퀀스 번호)를 1 증가 시킨 후 자신의 ack(승인 번호) 필드에 담아서 보내는데, “지금 이 패킷이 니가 전에 보낸 시퀀스 번호의 다음으로 이어지는 패킷이야”라고 말하고 있는 것이다.

이 3회의 통신이 바로 3 Way Handshake이다. 이 과정을 통해 클라이언트와 서버는 데이터를 주고 받을 준비가 되었다는 것을 서로에게 알려주고 이후 데이터 전송에 필요한 시퀀스 번호를 알 수 있게 된다. 연결을 끊을 때도 마찬가지로 이와 비슷한 과정인 4 Way Handshake를 거치고 나서야 세션을 종료할 수 있으며, 이때는 총 4회의 통신을 통해 연결을 종료한다.

✔ HTTP1 VS HTTP2

공통점 : TCP 사용

HTTP/1은 하나의 TCP 연결에 하나의 요청만 처리하고 연결을 끊어버렸기 때문에 매 요청마다 이 번거로운 핸드쉐이크를 거쳐야 했다. 그래서 HTTP/2에서는 핸드쉐이크를 최소화하기 위해서 단일 TCP 연결을 유지하면서 여러 개의 요청을 처리할 수 있도록 변경된 것이다.

결국 HTTP/1에서 HTTP/2로 넘어갈 때도 핸드쉐이크 과정 자체는 건드리지 않았고 단지 핸드쉐이크가 발생하는 횟수를 최소화함으로써 레이턴시를 줄인 것이다. 이는 TCP를 사용하는 이상 핸드쉐이크가 반드시 필요한 과정이기 때문에 건드리지 못한 것이다.

✔ 문제점

HOLB(Head of line Blocking)

TCP를 사용한 통신에서 패킷은 무조건 정확한 순서대로 처리되어야 한다. 수신 측은 송신 측과 주고받은 시퀀스 번호를 참고하여 패킷을 재조립해야하기 때문이다.

그래서 통신 중간에 패킷이 손실되면 완전한 데이터로 다시 조립할 수 없기 때문에 절대로 그냥 넘어가지 않는다. 무조건 송신 측은 수신 측이 패킷을 제대로 다 받았다는 것을 확인한 후, 만약 수신 측이 제대로 패킷을 받지 못했으면 해당 패킷을 다시 보내야 한다.

또한 패킷이 처리되는 순서 또한 정해져있으므로 이전에 받은 패킷을 파싱하기 전까지는 다음 패킷을 처리할 수도 없다. 이렇게 패킷이 중간에 유실되거나 수신 측의 패킷 파싱 속도가 느리다면 통신에 병목이 발생하게 되는 현상을 HOLB라고 부르는 것이다. 이건 TCP 자체의 문제이므로 HTTP/1 뿐만 아니라 HTTP/2도 가지고 있는 문제이다.

이런 문제들을 해결하기 위해 HTTP/3는 UDP를 기반으로 만들어진 프로토콜인 QUIC 위에서 작동하는 것을 선택한 것이다.

✅ UDP

  • User Datagram Protocol
  • 데이터그램 방식을 사용:
    • 각각의 패킷 간의 순서가 존재하지 않는 독립적인 패킷을 사용
    • 데이터그램 방식은 패킷의 목적지만 정해져있다면 중간 경로는 어딜 타든 신경쓰지 않기 때문에 종단 간의 연결 설정 또한 하지 않는다.
    • 즉, 핸드쉐이크 과정이 필요없다는 것이다.
  • UDP의 진짜 장점은 바로 커스터마이징이 용이
    • TCP의 경우 워낙 오래 전에 설계되기도 했고, 이런 저런 기능이 워낙 많이 포함된 프로토콜이다보니 이미 헤더가 거의 풀방이다. TCP에 기본적으로 정의되어 있는 기능 외에 다른 추가 기능을 구현하고 싶다면 가장 하단에 있는 옵션(Options) 필드를 사용해야 하는데, 옵션 필드도 무한정 배당 해줄 수는 없으니 최대 크기를 320 bits로 정해놓았다.

✅ HTTP3

HTTP/3가 UDP를 사용함으로써 기존 프로토콜보다 나아진 점

  1. 연결 설정 시 레이턴시 감소
    QUIC은 TCP를 사용하지 않기 때문에 통신을 시작할 때 번거로운 3 Way Handshake 과정을 거치지 않아도 된다. 반면 QUIC은 클라이언트가 서버에 어떤 신호를 한번 주고, 서버도 거기에 응답하기만 하면 바로 본 통신을 시작할 수 있다.

    첫번째 핸드쉐이크를 거칠 때, 연결 설정에 필요한 정보와 함께 데이터도 보내버리는 것이다. TCP+TLS는 데이터를 보내기 전에 신뢰성있는 연결과 암호화에 필요한 모든 정보를 교환하고 유효성을 검사한 뒤에 데이터를 교환하지만, QUIC은 묻지도 따지지도 않고 그냥 바로 데이터부터 꽂아버리고 시작한다.

  2. 패킷 손실 감지에 걸리는 시간 단축
    QUIC도 TCP와 마찬가지로 전송하는 패킷에 대한 흐름 제어를 해야한다. 왜냐면 QUIC든 TCP든 결국 본질적으로는 ARQ 방식을 사용하는 프로토콜이기 때문이다. 통신과정에서 발생한 에러를 어떻게 처리할 것인지를 이야기하는 것인데, ARQ 방식은 에러가 발생하면 재전송을 통해 에러를 복구하는 방식을 말하는 것이다.

    TCP는 여러 ARQ 방식 중에서 Stop and Wait ARQ 방식을 사용하고 있다. 이 방식은 송신 측이 패킷을 보낸 후 타이머를 사용하여 시간을 재고, 일정 시간이 경과해도 수신 측이 적절한 답변을 주지 않는다면 패킷이 손실된 것으로 판단하고 해당 패킷을 다시 보내는 방식이다.

    TCP에서 패킷 손실 감지에 대한 대표적인 문제는 송신 측이 패킷을 수신측으로 보내고 난 후 얼마나 기다려줄 것인가, 즉 타임 아웃을 언제 낼 것인가를 동적으로 계산해야한다는 것이다. 이때 이 시간을 RTO(Retransmission Time Out)라고 하는데, 이때 필요한 데이터가 바로 RTT(Round Trip Time)들의 샘플들이다.

    한번 패킷을 보낸 후 잘 받았다는 응답을 받을 때 걸렸던 시간들을 측정해서 동적으로 타임 아웃을 정하는 것이다. 즉, RTT 샘플을 측정하기 위해서는 반드시 송신 측으로 부터 ACK를 받아야하는데, 정상적인 상황에서는 딱히 문제가 없으나 타임 아웃이 발생해서 패킷 손실이 발생하게 되면 RTT 계산이 애매해진다.

    이때 이 ACK가 어느 패킷에 대한 응답인지 알기 위해서는 타임스탬프를 패킷에 찍어주는 등 별도의 방법을 또 사용해야하고, 또 이를 위한 패킷 검사도 따로 해줘야 한다. 이를 재전송 모호성(Retransmission Ambiguity)이라고 한다.

    이 문제를 해결하기 위해 QUIC는 헤더에 별도의 패킷 번호 공간을 부여했다. 이 패킷 번호는 패킷의 전송 순서 자체만을 나타내며, 재전송시 동일한 번호가 전송되는 시퀀스 번호와는 다르게 매 전송마다 모노토닉하게 패킷 번호가 증가하기 때문에, 패킷의 전송 순서를 명확하게 파악할 수 있다.

    TCP의 경우 타임스탬프를 사용할 수 있는 상황이라면 타임스탬프를 통해 패킷의 전송 순서를 파악할 수 있지만, 만약 사용할 수 없는 경우 시퀀스 번호에 기반하여 암묵적으로 전송 순서를 추론할 수 밖에 없지만, QUIC는 이런 불필요한 과정을 패킷마다 고유한 패킷 번호를 통해 타파함으로써 패킷 손실 감지에 걸리는 시간을 단축할 수 있었다.

  3. 멀티플렉싱을 지원
    멀티플렉싱(Multiplexing)은 위에서 TCP의 단점으로 언급했던 HOLB(Head of Line Blocking)을 방지하기 때문에 매우 중요하다. 여러 개의 스트림을 사용하면, 그 중 특정 스트림의 패킷이 손실되었다고 하더라도 해당 스트림에만 영향을 미치고 나머지 스트림은 멀쩡하게 굴릴 수 있기 때문이다.

    참고로 멀티플렉싱은 여러 개의 TCP 연결을 만든다는 의미가 아니라, 단일 연결 안에서 몇 가지 얌생이를 사용하여 여러 개의 데이터를 섞이지 않게 보내는 기법이다. 이때 각각의 데이터의 흐름을 스트림이라고 하는 것이다.

    HTTP/1의 경우는 하나의 TCP 연결에 하나의 스트림만 사용하기 때문에 HOLB 문제에서 벗어날 수 없었다. 또한 한번의 전송이 끝나게 되면 연결이 끊어지기 때문에 다시 연결을 만들기 위해서는 번거로운 핸드쉐이크 과정을 또 겪어야 했다.

    HTTP/2는 하나의 TCP 연결 안에서 여러 개의 스트림을 처리하는 멀티플렉싱 기법을 도입하여 성능을 끌어올린 케이스이다. 이 경우 한번의 TCP 연결로 여러 개의 데이터를 전송할 수 있기 때문에 핸드쉐이크 횟수도 줄어들게 되어 효율적인 데이터 전송을 할 수 있게 된다.

    QUIC 또한 HTTP/2와 동일하게 멀티플렉싱을 지원하기 때문에, 이런 이점을 그대로 가져가고 있다. 혹여나 하나의 스트림에서 문제가 발생한다고 해도 다른 스트림은 지킬 수 있게 되어 이런 문제에서 자유로울 수 있다.

  4. 클라이언트의 IP가 바뀌어도 연결이 유지됨
    TCP의 경우 소스의 IP 주소와 포트, 연결 대상의 IP 주소와 포트로 연결을 식별하기 때문에 클라이언트의 IP가 바뀌는 상황이 발생하면 연결이 끊어져 버린다. 연결이 끊어졌으니 다시 연결을 생성하기 위해 결국 눈물나는 3 Way Handshake 과정을 다시 거쳐야한다는 것이고, 이 과정에서 다시 레이턴시가 발생한다.

    게다가 요즘에는 모바일로 인터넷을 사용하는 경우가 많기 때문에 Wi-fi에서 셀룰러로 전환되거나 그 반대의 경우, 혹은 다른 Wi-fi로 연결되는 경우와 같이 클라이언트의 IP가 변경되는 일이 굉장히 잦아서 이 문제가 더 눈에 띈다.

    반면 QUIC은 Connection ID를 사용하여 서버와 연결을 생성한다. Connection ID는 랜덤한 값일 뿐, 클라이언트의 IP와는 전혀 무관한 데이터이기 때문에 클라이언트의 IP가 변경되더라도 기존의 연결을 계속 유지할 수 있다. 이는 새로 연결을 생성할 때 거쳐야하는 핸드쉐이크 과정을 생략할 수 있다는 의미이다.

profile
꿈꿈

0개의 댓글