프론트 기술 질문 2. HTTP 버전별 특징

기운찬곰·2023년 8월 26일
0

프론트 기술 질문

목록 보기
2/10
post-thumbnail

Overview

이번에는 어떤 질문을 다뤄볼까 생각하다가 재밌어보이는 주제로 가져왔습니다. 바로 HTTP 버전별 역사와 특징에 대해 알아보려고 합니다. 음... 개인적으로 이런 면접 질문을 받아본 적은 없는거 같지만 한번쯤 다뤄볼만 한 주제인건 확실합니다. 아. 네트워크도 어느 정도 알아야겠네요.


HTTP/1.0

HTTP/1.0 은 1996년에 발표되었습니다. HTTP Request와 Response 형태는 다음과 같습니다. 단순하죠?

TCP를 기반으로 되어있었고 따라서 커넥션 수립을 위한 TCP 3-way Handshake 과정을 거쳐야 했습니다. 그리고 나서 요청과 응답이 이뤄지고 이후에는 연결이 끊어지게 됩니다. 즉, 요청을 한 번 보내려면 TCP 3-way Handshake를 반드시 거쳐야 했기 때문에 여간 불편한게 아니겠죠?


HTTP/1.1

HTTP/1.1 은 1997년 초에 공개가 되었고 1999년에 발표되었습니다. HTTP의 첫번째 표준 버전이라고 볼 수 있습니다. HTTP/1.1은 모호함을 명확하게 하고 많은 개선 사항들을 도입했습니다:

참고 : https://developer.mozilla.org/ko/docs/Web/HTTP/Connection_management_in_HTTP_1.x

Persistent connection

첫번째로 커넥션 재사용이 가능하게 했습니다. Persistent connection 이라고도 하죠. 모든 요청에 대해 비용이 많이 드는 TCP 3-way Handshake을 시작할 필요가 없기 때문에 요청 지연 시간을 줄여줍니다.

참고 : https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Connection
참고 : https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Keep-Alive

그리고 이와 관련한 속성으로 헤더에 Connection과 keep-alive 가 등장했습니다.

Connection 일반 헤더는 현재의 전송이 완료된 후 네트워크 접속을 유지할지 말지를 제어합니다. 만약 전송된 값이 keep-alive면, 연결은 지속되고 끊기지 않으며, 동일한 서버에 대한 후속 요청을 수행할 수 있습니다. Keep-Alive 일반 헤더는 송신자가 연결에 대한 타임아웃과 요청 최대 개수를 어떻게 정했는지에 대해 알려줍니다.

HTTP/1.1 200 OK
Connection: Keep-Alive  ✅
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Thu, 11 Aug 2016 15:23:13 GMT
Keep-Alive: timeout=5, max=1000  ✅
Last-Modified: Mon, 25 Jul 2016 04:32:39 GMT
Server: Apache

(body)

하지만 HTTP/2.0 부터는 비표준이 된 거 같습니다. 물론 성능 향상은 확실하지만 잘못 사용했다가는 모든 요청 마다 연결을 유지해야 하기 때문에 대량 접속 시 메모리를 많이 사용하게 되어 효율이 떨어질 수 있습니다. 그리고 "멍청한(Dumb) 프록시" 문제가 발생할 수도 있습니다. 아무튼 설계상 문제가 있다고 하네요.

Connection과 keep-alive만 비표준이 된 것일 뿐 Persistent Connection 개념은 여전히 유효합니다. (오해 주의)

Pipelining

두번째 큰 변화는 Pipelining (파이프라이닝) 기법입니다. 이를 이용하면 응답조차도 기다리지 않고 연속적인 요청을 보내서 네트워크 지연을 더욱 줄일 수 있습니다. 응답은 요청과 동일한 순서로 수신되어야 합니다.

하지만 올바르게 구현되기 까다롭고 사이에 있는 많은 프록시 서버가 Pipelining을 제대로 처리하지 못했습니다.

또한 HOL(Head-of-line blocking) 문제에 영향을 받습니다. HOL을 쉽게 설명하자면 고속도로에서 하나가 막히기 시작하면 이후에 줄줄히 막히는 것과 같은 현상입니다. 후속 요청은 이전 요청이 완료될 때까지 기다려야 하기 때문입니다.

결국 Connection과 keep-alive랑 마찬가지로 Pipelining은 모던 브라우저에서 기본적으로 활성화되어있지 않습니다. 파이프라이닝의 실패로 더 나은 커넥션 관리 모델(멀티플렉싱)이 고안되었고, 이는 HTTP/2에 포함되었습니다.


HTTP/2.0

HTTP/2.0은 2015년에 발표되었습니다. 몇 년에 걸쳐, 웹 페이지는 매우 복잡해지면서, 진정한 애플리케이션이 됩니다. 디스플레이되는 시각적 미디어의 양에 덧붙여 상호작용을 추가하기 위한 스크립트의 양과 크기는 점점 더 많이 증가하고 있습니다. 더 많은 데이터들이 더 많은 요청 너머로 전송되고 있습니다. HTTP/1.1 커넥션은 올바른 순서로 전송되는 요청을 필요로 합니다. HTTP 파이프라이닝은 디플로이 악몽임이 확실해졌습니다.

HTTP/2.0 소개

참고 : https://web.dev/performance-http2/

HTTP/2의 주요 목표는 완전한 요청 및 응답 다중화를 가능하게 함으로써 지연 시간을 줄이고, HTTP 헤더 필드의 효율적인 압축을 통해 프로토콜 오버헤드를 최소화하며, 요청 우선순위 지정 및 서버 푸시에 대한 지원을 추가하는 것입니다.

HTTP/2는 HTTP 메서드, 상태 코드, URI 및 헤더 필드와 같은 모든 핵심 개념은 그대로 유지됩니다. 대신, HTTP/2는 데이터가 포맷(프레임화)되고 클라이언트와 서버 간에 전송되는 방식을 수정하며 새로운 프레임화 계층 내에서 애플리케이션으로부터 모든 복잡성을 숨깁니다. 이에 따라 기존의 모든 애플리케이션을 수정 없이 전달할 수 있게 됐습니다.

참고로 HTTP/2 이전에 2009년 구글에서 SPDY라는 실험적인 프로토콜을 개발합니다. 주요 목표는 HTTP/1.1의 잘 알려진 성능 제한을 해결함으로써 웹 페이지의 부하 지연을 줄이는 것으로 이는 HTTP/2에 많은 영향을 끼쳤습니다.

Binary framing layer

HTTP/2의 모든 성능 향상의 핵심에는 새로운 Binary framing 계층이 있습니다. 그것은 텍스트 프로토콜이라기 보다는 이진 프로토콜입니다.

메소드 및 헤더와 같은 HTTP 시맨틱스는 영향을 받지 않지만 전송 중에 인코딩되는 방식은 다릅니다. 행으로 구분되는 평문 HTTP/1.x 프로토콜과 달리, 모든 HTTP/2 통신은 더 작은 메시지와 프레임으로 분할되며, 각각은 이진 형식으로 인코딩됩니다.

결과적으로, 클라이언트와 서버는 서로를 이해하기 위해 새로운 이진 인코딩 메커니즘을 사용해야 합니다: HTTP/1.x 클라이언트는 HTTP/2 전용 서버를 이해하지 못할 것이고, 그 반대도 마찬가지입니다. 감사하게도, 클라이언트와 서버가 당사를 대신하여 필요한 모든 프레임 작업을 수행하기 때문에 당사의 애플리케이션은 이러한 모든 변화를 전혀 인식하지 못하고 있습니다.

Streams, messages, and frames

새로운 이진 프레이밍 메커니즘의 도입은 클라이언트와 서버 간에 데이터가 교환되는 방식을 변경했습니다. 이 과정을 설명하기 위해 HTTP/2 용어를 숙지해 보겠습니다:

  • Stream: 하나 이상의 메시지를 전송할 수 있는 수립된 연결 내 바이트의 양방향 흐름입니다.
  • Message: 논리적 요청 또는 응답 메시지에 매핑되는 전체 프레임 시퀀스입니다.
  • Frame: HTTP/2에서 가장 작은 통신 단위는 각각 프레임 헤더를 포함하며, 최소 프레임이 속하는 스트림을 식별합니다.

이들 용어의 관계는 다음과 같이 요약할 수 있습니다:

  • 모든 통신은 임의의 수 양방향 스트림을 전송할 수 있는 단일 TCP 연결을 통해 수행됩니다.
  • 각 스트림에는 고유한 식별자와 양방향 메시지를 전달하는 데 사용되는 선택적 우선 순위 정보가 있습니다.
  • 각 메시지는 하나 이상의 프레임으로 구성된 요청 또는 응답과 같은 논리적 HTTP 메시지입니다.
  • 프레임은 HTTP 헤더, 메시지 페이로드 등과 같은 특정 유형의 데이터를 전송하는 최소 통신 단위입니다. 각각의 프레임의 헤더에 내장된 스트림 식별자를 통해 서로 다른 스트림의 프레임들이 interleaving(섞이다, 끼워 넣기) 된 후 재조립될 수 있습니다.

간단히 말해서, HTTP/2는 HTTP 프로토콜 통신을 이진 인코딩된 프레임의 교환으로 분해하고, 이 프레임들은 특정 스트림에 속하는 메시지들에 매핑되며, 이들 모두는 단일 TCP 연결 내에서 다중화됩니다. 이것은 HTTP/2 프로토콜이 제공하는 다른 모든 기능과 성능 최적화를 가능하게 하는 기반입니다.

Multiplexing streams

HTTP/1.x의 경우 클라이언트가 성능 향상을 위해 여러 병렬 요청을 수행하려면 여러 TCP 연결을 사용했습니다. 이것은 HOL 문제와 기본 TCP 연결의 비효율적인 사용을 초래합니다.

HTTP/2의 새로운 binary framing 계층은 이러한 제한을 제거하고, 클라이언트와 서버가 HTTP 메시지를 독립적인 프레임으로 분해하여 interleave한 다음 다른 쪽에서 다시 조립할 수 있도록 함으로써 완전한 요청과 응답 다중화를 가능하게 합니다. (⭐️ 이게 핵심이네요)

HTTP/2의 새로운 binary framing 계층은 HTTP/1.x에서 발견되는 HOL 문제를 해결하고 요청 및 응답의 병렬 처리 및 전달을 가능하게 하기 위해 여러 개의 연결이 필요하지 않습니다. 결과적으로, 이를 통해 애플리케이션을 더 빠르고, 더 간단하고, 더 저렴하게 구축할 수 있습니다.

Server push

HTTP/2의 또 다른 강력한 새로운 특징은 단일 클라이언트 요청에 대해 여러 응답을 보낼 수 있는 서버의 기능입니다. 즉, 원래 요청에 대한 응답 외에, 클라이언트가 각각을 명시적으로 요청할 필요 없이, 서버는 추가 리소스를 클라이언트에 푸시할 수 있습니다.

쉽게 말해 클라이언트가 html 요청을 하면 서버는 html 뿐만 아니라 그 외 필요한 것들을 미리 분석해서 같이 보내줄 수 있습니다.

왜 우리는 브라우저에 그런 메커니즘이 필요합니까? 일반적인 웹 애플리케이션은 수십 개의 리소스로 구성되며, 이들 리소스는 모두 서버가 제공한 문서를 검사하여 클라이언트에 의해 검색됩니다. 결과적으로 추가 대기 시간을 없애고 서버가 관련 리소스를 미리 확보하도록 하는 것은 어떨까요? 서버는 클라이언트가 어떤 리소스를 요구할지 이미 알고 있습니다. 이것이 바로 Server push 기능입니다.


HTTP/3.0

HTTP는 2020년 초안으로 시작되어 2022년 6월 발표되었습니다. 기본 전송 프로토콜인 TCP/TLS 대신 UDP 기반인 QUIC가 사용됩니다.

왜 QUIC 프로토콜은 TCP대신 UDP일까?

참고 : https://developer.mozilla.org/ko/docs/Glossary/QUIC

왜 안정적인 TCP 대신 UDP를 사용했을까요? TCP는 많은 운영 체제 커널에 내장되어 있기 때문에 변경사항을 실험하고 수정을 구현하는 것에 시간이 많이드는 과정입니다. 따라서 이미 많은 것이 내장되어있는 TCP보다는 하얀 도화지 같은 UDP를 기반으로 QUIC을 만들어 개발자는 더 빠르게 실험을 할 수 있고, 새로운 것을 시도할 수 있게 되었습니다.

QUIC은 HTTP/2의 의미론적 지원을 위해 설계되었습니다. 멀티플랙싱, 흐름 제어, 보안 및 혼잡 제어를 제공해줍니다. 다음은 QUIC의 중요한 기능입니다.

  • 연결 설정 시간 단축
  • 혼잡 제어 개선
  • Head of Line Blocking 없는 멀티플렉싱
  • 전달 오류 수정
  • 연결 마이그레이션

"현재는 QUIC를 지원하는 브라우저와 서버는 그리 많지 않습니다." 라고 적혀있긴 하지만 2023년 기준으로 봤을때 인기있는 서비스(구글, 유튜브, 넷플릭스, 인스타그램, 아마존 등)는 대부분 HTTP/3를 지원하는 거 같네요. 전체 사이트 기준으로는 26.6% 라고 합니다. - w3techs 참고

QUIC는 HOL 문제를 해결하는 것이 목적

참고 : https://ko.wikipedia.org/wiki/HTTP/3

"QUIC로의 전환은 헤드 오브 라인 블로킹이라는 HTTP/2의 주된 문제를 해결하는 것이 목적이다."

🤔 흠... HTTP/2.0에서 해결된 줄 알았던 HOL 문제가 아직 제대로 해결이 안되었던거네요?

참고 : https://blog.cloudflare.com/ko-kr/http3-the-past-present-and-future-ko-kr/

TCP의 역할은 전체 데이터를 순서대로 한 곳에서 다른 곳으로 전달하는 것입니다. 데이터 일부를 담고 있는 TCP 패킷이 네트워크 경로 상에서 손실 되면 데이터 스트림에 누락 구간이 생기고 TCP는 손실이 탐지 되었을 때 영향받은 패킷만을 재전송하려 합니다. 그렇게 하는 동안 분실과 관계 없는 완전히 독립된 HTTP 요청에 속하는 경우에도, 분실된 데이터 이후 성공적으로 받은 데이터는 어플리케이션으로 전달되지 못합니다. TCP는 잃어버린 데이터 없이 어플리케이션이 진행 가능한 지 알지 못하므로 불필요한 지연이 발생하게 됩니다. 이는 "HoLB" (head-of-line blocking)이라고 알려진 문제 입니다.

QUIC 스트림은 동일 QUIC 연결을 공유 하므로 새 스트림을 만들 때 추가적인 핸드쉐이크나 슬로우 스타트가 필요하지 않습니다. QUIC 스트림은 독립적으로 전달되어 어떤 스트림에 패킷 손실이 있는 경우에도 다른 스트림에는 영향이 없습니다. 이는 QUIC 패킷이 UDP 데이터그램 위에 캡슐화되어 있기 때문 입니다. 이것이 QUIC가 전송 계층에서 HOL 문제를 해결하는 방법입니다.

그림을 보니 좀 쉽게 이해가 가네요.

QUIC는 모바일에서 인터넷을 많이 사용하는 요즘 환경에 대응하기 위해 설계되었습니다. 스마트폰을 소지한 사람들이 하루 종일 이동하면서 끊임없이 한 네트워크에서 다른 네트워크로 전환합니다. TCP를 이용하면 한 네트워크에서 다른 네트워크로의 연결 핸드오프가 느립니다. QUIC는 connection ID라는 개념을 구현하여 IP주소와 네트워크 인터페이스 간에 빠르고 안정적으로 이동할 수 있도록 합니다.


마치면서

HTTP 버전 별 역사를 보면 그 시대 환경이 바뀐 것을 볼 수 있네요. 환경에 따라 필요에 의해 버전이 바뀐거고요. 꽤나 재미있는 시간이었습니다.


참고 자료

profile
velog ckstn0777 부계정 블로그 입니다. 프론트 개발 이외의 공부 내용을 기록합니다. 취업준비 공부 내용 정리도 합니다.

0개의 댓글

관련 채용 정보