HTTP/1 부터 HTTP/3 까지 알아보기

ziyoonee·2021년 2월 7일
0

etc

목록 보기
2/14

성능 관련 이슈 때문에 항상 실무에서 이미지 스프라이트, 도메인 샤딩 등을 적용해왔다.
하지만 드라마틱한 효과는 나타나지 않았고 말로만 들어온 H2적용의 필요성을 느끼게 되어 정리해본다.

HTTP란?

HTTP(HyperText Transfer Protocol)
웹에서 정보를 주고받을 수 있는 프로토콜

HTTP/0.9

버전번호가 따로 없는 상태로 발표되었던 초기 HTTP는 요청이 단일 라인으로 구성되며 가능한 메서드는 get이 유일했다.
Header 따위는 없었고, 그 때문에 오직 HTML 파일만 전송이 가능했으며, 상태 확인을 위한 코드도 존재하지 않았다.
( HTTP 1.0가 나오면서 0.9가 됨 )

HTTP/1.0

제한적인 기능을 개선해 아래와 같은 기능이 추가 되었다.

  • 요청에 버전 정보가 붙어서 붙어서 전송되기 시작
  • 응답 시작 부분에 상태 코드가 추가됨
  • 모든 요청과 응답에 헤더 개념이 추가됨

HTTP/1.1

1.0이 발표될 당시에 다양한 표준화가 진행되고 있었고, 1.0 발표가 된지 몇달 지나지 않아 HTTP의 첫번째 표준버전인 1.1이 발표되었다. HTTP/1.1 버전은 많은 개선사항을 도입하였다.

  • Connection Keep-Alive (기존 연결에 대해서 handshake 생략가능)
  • 파이프라이닝 추가, 이전 요청에 대한 응답이 완전히 전송되기 전에 다음 전송을 가능하게 하여 레이턴시를 낮춤
  • 청크된 응답 지원(응답 조각)
  • 캐시 제어 메커니즘
  • 언어, 인코딩 타입등을 포함한 컨텐츠 전송
  • 동일 IP 주소에 다른 도메인을 호스트하는 기능 가능 (HOST header)

HTTP는 TCP 연결 기반 위에서 동작하는 프로토콜로 신뢰성 확보를 위해 연결을 맺고 끊는 데 있어서 Handshake 가 이루어진다.
거기에다 HTTP는 비연결성 프로토콜이기 때문에 한번의 연결로 한 번의 요청과 응답을 하고 응답이 끝나면 연결을 끊어 버렸고 연결을 맺고 끊을 때마다 Handshake를 하기 때문에 비연결성 프로토콜에선 overhead 가 생겼다. 그래서 HTTP/1.1에서 Keep-alive 기능이 추가되어 한 번 맺어졌던 연결을 끊지 않고 지속적으로 유지하여 불필요한 핸드 셰이크를 줄여 성능을 개선할 수 있게 되었다.

HTTP/1.1의 단점

  • HTTP HOLB
    HTTP/1.1의 파이프라이닝 이라는 기술은 하나의 커넥션에서 한 번에 순차적인 여러 요청을 연속적으로 하고 그 순서에 맞춰 응답을 받는 방식으로 지연 시간을 줄이는 방법이다.
    순차적으로 데이터를 요청하고 받아야 하다 보니 먼저 받은 요청이 끝나지 않으면 그 뒤에 있는 요청의 처리가 아무리 빨리 끝나도 먼저 온 요청이 끝날 때까지 기다려야 하는 HTTP의 HOL(Head Of Line) Blocking 문제가 발생했다. 그래서 모던 브라우저들은 대부분은 파이프라이닝을 사용하지 못하도록 막아 놓았고 H1으로 통신할 때 클라이언트(브라우저)가 요청을 병렬로 하기 위해서 6-8개(브라우저마다 다름)의 커넥션을 이용해 데이터를 가져오는 방식으로 성능을 개선하고 있다.

  • RTT(Round Trip Time)
    TCP상에서 동작하는 HTTP의 특성상 Handshake 가 반복적으로 일어나고 또한 불필요한 RTT증가 와 네트워크 지연을 초래하여 성능을 저하 시키게 된다.

  • 무거운 Header 구조
    http/1.1의 헤더에는 많은 메타정보들이 저장되어져 있다. 사용자가 방문한 웹페이지는 다수의 http요청이 발생하게 되는데 이 경우 매 요청시 마다 중복된 헤더값을 전송하게 되며 또한 해당 domain에 설정된 cookie정보도 매 요청시 마다 헤더에 포함되어 전송되어 전송값보다 헤더가 큰경우도 있다.

SPDY

구글은 더 빠른 Web을 실현하기 위해 Latency 관점에서 HTTP를 고속화한 SPDY(스피디) 라 불리는 새로운 프로토콜을 구현했다.
SPDY는 HTTP를 대치하는 프로토콜이 아니고 HTTP를 통한 전송을 재 정의하는 형태로 구현 되었다.
SPDY는 실제로 HTTP/1.1에 비해 상당한 성능 향상과 효율성을 보여줬고 이는 HTTP/2 초안의 참고 규격이 되었다. HTTP/2의 비표준이라고 생각하면 될 것 같다!

HTTP/2

http2 공식 github 페이지의 서문을 보면 http2의 목적을 명확히 알 수 있다.

What is HTTP/2?
HTTP/2 is a replacement for how HTTP is expressed "on the wire." It is not a ground-up rewrite of the protocol; HTTP methods, status codes and semantics are the same, and it should be possible to use the same APIs as HTTP/1.x (possibly with some small additions) to represent the protocol.
The focus of the protocol is on performance; specifically, end-user perceived latency, network and server resource usage. One major goal is to allow the use of a single connection from browsers to a Web site.
The basis of the work was SPDY, but HTTP/2 has evolved to take the community's input into account, incorporating several improvements in the process.

요약하자면 완전히 새로운 프로토콜이 아닌 SPDY의 개선사항을 적용해 수정된 성능향상에 초점을 맞춘 프로토콜 이라고 생각하면 될것같다.

  • Multiplexed Streams
    한 커넥션으로 동시에 여러 개의 메세지를 주고 받을 있으며, 응답은 순서에 상관없이 stream으로 주고 받음
    HTTP/1.1의 Connection Keep-Alive, Pipelining의 개선했다.

  • Stream Prioritization
    클라이언트가 요청한 HTML문서 안에 CSS파일 1개와 Image파일 2개가 존재하고 이를 클라이언트가 각각 요청하고 난 후 Image파일보다 CSS파일의 수신이 늦어지는 경우 브라우저의 렌더링이 늦어지는 문제가 발생하는데 HTTP/2의 경우 리소스간 의존관계(우선순위)를 설정하여 이런 문제를 해결했다.

  • Server Push
    서버는 클라이언트의 요청에 대해 요청하지도 않은 리소스를 보내줄 수 있게 되었다.
    클라이언트(브라우저)가 HTML문서를 요청하고 해당 HTML에 여러 개의 리소스(CSS, Image...) 가 포함되어 있는 경우 HTTP/1.1에서 클라이언트는 요청한 HTML문서를 수신한 후 HTML문서를 해석하면서 필요한 리소스를 재 요청하는 반면 HTTP/2에서는 Server Push기법을 통해서 클라이언트가 요청하지 않은 (HTML문서에 포함된 리소스) 리소스를 Push 해주는 방법으로 클라이언트의 요청을 최소화 해서 성능 향상을 이끌어 냈다.
    PUSH_PROMISE 라고 부르며 PUSH_PROMISE를 통해서 서버가 전송한 리소스에 대해선 클라이언트는 요청을 않는다.

  • Header Compression
    HTTP/2는 Header 정보를 압축하기 위해 HPACK 압축방식을 이용
    HTTP/2에선 Header에 중복값이 존재하는 경우 Static/Dynamic Header Table 개념을 사용하여 중복 Header를 검출하고 중복된 Header는 index값만 전송하고 중복되지 않은 Header정보의 값은 Huffman Encoding 기법으로 인코딩 처리 하여 전송한다.

HTTP/2의 단점

하지만 HTTP2는 여전히 TCP를 이용하기 때문에 Handshake의 RTT(Round Trip Time)로인한 Latency(지연시간), TCP의 HOLB 문제는 해결 할 수 없다.

QUIC

QUIC은 Quick UDP Internet Connections 의 약자이며, UDP를 기반으로
TCP + TLS + HTTP 의 기능을 모두 구현하는 프로토콜이다.
구글에서 개발했던 SPDY 기술이 HTTP/2의 기반 기술이었는데 역시 구글에서 개발한 QUIC이 HTTP/3의 기반 기술이 되었다.

HTTP/3

HTTP/3는 HTTP(Hypertext Transfer Protocol)의 세 번째 메이저 버전으로, 기존의 HTTP/1, HTTP/2와는 다르게 UDP 기반의 프로토콜인 QUIC 을 사용하여 통신하는 프로토콜이다. HTTP/3와 기존 HTTP 들과 가장 큰 차이점이라면 TCP가 아닌 UDP 기반의 통신을 한다는 것이다.
UDP를 사용하지만 그렇다고 기존의 신뢰성 있는 통신이라는 타이틀을 포기한 것은 아니다.

구글이 QUIC을 만들 때 UDP를 선택한 이유에는 기존의 TCP를 수정하기가 어려운데다가, 백지 상태나 다름 없는 UDP를 사용함으로써 QUIC의 기능을 확장하기 쉬웠기 때문이라고 한다.

  • RTT 감소로인한 지연시간 단축
    QUIC은 TCP를 사용하지 않기 때문에 통신을 시작할 때 번거로운 3 Way Handshake 과정을 거치지 않아도 된다. 클라이언트가 보낸 요청을 서버가 처리한 후 다시 클라이언트로 응답해주는 사이클을 RTT(Round Trip Time)이라고 하는데, TCP는 연결을 생성하기 위해 기본적으로 1 RTT가 필요하고, 여기에 TLS를 사용한 암호화까지 하려고 한다면 TLS의 자체 핸드쉐이크까지 더해져 총 3 RTT가 필요하다.

    반면 QUIC은 첫 연결 설정에 1 RTT만 소요된다. 그 이유는 연결 설정에 필요한 정보와 함께 데이터도 보내버리기 때문이다. 클라이언트가 서버에 어떤 신호를 한번 주고, 서버도 거기에 응답하기만 하면 바로 본 통신을 시작할 수 있다는 것이다.

    단, 클라이언트가 서버로 첫 요청을 보낼 때는 서버의 세션 키를 모르는 상태이기 때문에 목적지인 서버의 Connection ID를 사용하여 생성한 특별한 키인 초기화 키(Initial Key)를 사용하여 통신을 암호화 한다.

    그리고 한번 연결에 성공했다면 서버는 그 설정을 캐싱해놓고 있다가, 다음 연결 때는 캐싱해놓은 설정을 사용하여 바로 연결을 성립시키기 때문에 0 RTT만으로 바로 통신을 시작할 수도 있다. 이런 점들 때문에 QUIC은 기존의 TCP+TLS 방식에 비해 지연시간을 더 줄일 수 있었던 것이다.

    TCP Fast Open + TLS 1.3 으로 구현이 되긴하지만 주고 받는 데이터가 큰 경우 QUIC가 유리하다.
  • 패킷 손실 감지에 걸리는 시간 단축
    QUIC도 TCP와 마찬가지로 전송하는 패킷에 대한 흐름 제어를 해야한다. 통신과정에서 발생한 에러를 재전송을 통해 에러를 복구하는 ARQ 방식을 사용하기 때문이다.

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

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

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

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

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

  • 클라이언트의 IP가 바뀌어도 연결이 유지됨
    TCP의 경우 소스의 IP 주소와 포트, 연결 대상의 IP 주소와 포트로 연결을 식별하기 때문에 클라이언트의 IP가 바뀌는 상황이 발생하면 연결이 끊어져 버린다. 연결이 끊어졌으니 다시 연결을 생성하기 위해 결국 Handshake 과정을 다시 거쳐야한다는 것이고, 이 과정에서 다시 레이턴시가 발생한다.
    (모바일의 경우 Wi-fi , 셀룰러 전환으로 인해 ip 변경이 잦음)

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


참고자료

https://blog.cloudflare.com/announcing-support-for-http-2-server-push-2/
https://www.whatap.io/ko/blog/38/
https://evan-moon.github.io/2019/10/08/what-is-http3/#3-way-handshake
https://ykarma1996.tistory.com/86

profile
기록✍🏻

1개의 댓글

comment-user-thumbnail
2021년 2월 7일

잘정리하셨네요
유익한 정보 감사합니다!

답글 달기