[HTTP] 10장: HTTP 모든 버전

서정범·2024년 1월 18일
0

HTTP

목록 보기
9/13

목표

해당 단원에서는 HTTP/2.0에 대해서 다루고 있습니다. 하지만, 여기서 정리할 것은 HTTP/1.0, HTTP/1.1, HTTP/2.0 그리고 HTTP/3.0까지 정리를 해볼 예정입니다.

여기서는 시간순으로 정리를 하면서, 이전 버전에 어떠한 기능들이 있었고 이것의 문제점을 파악하고 어떻게 개선된 형태로 다음 버전이 등장하였는지에 대해 초점을 맞출 것입니다.

HTTP

먼저, HTTP에 대해서 다시 한번 정리하고 들어갑시다.

HTTP(HyperText Transfer Protocol)는 월드 와이드 웹(WWW)에서 데이터를 주고받기 위한 프로토콜입니다. 이 프로토콜은 웹 브라우저와 웹 서버간에 통신을 가능하게 합니다. HTTP의 주요 특징과 구성 요소들은 다음과 같습니다.

주요 개념(특징)

  • 프로토콜(Protocol): 클라이언트(주로 웹 브라우저)와 서버 간에 문서와 기타 리소스를 주고 받는데 사용되는 규칙의 집합입니다.
  • 상티 비저장(Stateless): HTTP는 상태를 유지하지 않는 프로토콜입니다. 즉, 각 요청은 독립적이며, 이전 요청의 정보를 기억하지 않습니다. (세션과 쿠키를 통해 유지 가능)
  • 클라이언트-서버 모델: 클라이언트가 서버에게 요청(request)를 보내고, 서버가 이에 대한 응답(response)를 제공합니다.

주요 요소

  1. 메서드(Method)
  2. 상태 코드(Status Code)
  3. 헤더(Headers)
  4. 버전(Version)
  5. URI(Uniform Resource Identifier)

HTTP/1.0

초기 HTTP인 0.9는 결함을 많이 가지고 있었습니다.

  • Method는 GET 방식만 지원
  • MIME 타입 X
  • HTTP 헤더 X
  • 버전 번호 X

본래 HTTP/0.9는 간단한 HTML 객체를 받아오기 위해 만들어진 것입니다.

문서를 주고 받기 위해선 SMTP, FTP, Telnet과 같은 것을 사용해야 됐습니다.

이것에 불편함을 느껴서 등장하게 된 것이 WWW(World Wide Web)이였고, 표현 방식으로는 HTML을 사용한 것이죠.

웹이 정상적으로 동작하기 위해서는 통신 방식을 규격화할 필요가 있었는데, 이를 위해 선택한 프로토콜이 HTTP였습니다. 이것을 목표로 빠르게 성장하게 됩니다.

HTTP/1.0이 등장하게 되는데, 이것은 처음으로 널리 쓰이기 시작한 HTTP 버전입니다.

HTTP/1.0은 이전 버전과 다르게 다음과 같은 것들이 추가되었습니다.

추가된 것

  • 버전 번호(Version)
  • 헤더(Headers)
  • 추가 메서드(Method)
  • 멀티미디어 객체 처리

요즘 사용하는 기능들이 추가된 것으로 보았을 때 굉장히 잘 나온 것 같지만 그렇지 않습니다.

급성장하던 시기에 만들어진 잘 동작하는 용례들의 모음에 가깝고, HTTP/1.0은 결코 잘 정의된 명세라고 보기 힘들었습니다.

HTTP/1.0+

월드 와이드 웹이 급성장하게 되면서 유명 웹 클라언트와 서버 들은 그에 따른 요구를 만족시킥 위해 발빠르게 HTTP에 기능을 추가했습니다.

  • "keep-alive"
  • 가상 호스팅 지원
  • 프록시 연결 지원
  • 등등..

HTTP/1.1

HTTP/1.1은 HTTP 설계의 구조적 결함 교정, 두드러진 성능 최적화, 잘못된 기능 제거에 집중했습니다.

뿐만 아니라 HTTP/1.1은 더 복잡해진 웹 애플리케이션과 배포를 지원합니다.

요즘 같이 기능들이 빠르게 추가되는 시대에서 보면 이러한 성장 속도가 빠른 것인지 의문이 들 수 있지만, HTTP는 굉장히 신중하게 설계되고 성장해온 케이스로 하위 호환성을 유지하기 위해서 굉장히 노력했습니다.

HTTP/1.1에서는 다음과 같은 기능이 추가되었습니다.

  • 병렬 커넥션(Parallel Connections)
    • 여러 개의 커넥션을 이용하고 대역폭을 공유하면서 동시에 처리합니다.
  • 지속 커넥션(Persistent Connections)
    • 여러 요청과 응답이 하나의 TCP 커넥션을 통해 이루어질 수 있게 되었습니다. 이는 네트워크 오버헤드를 감소시키고 성능을 향상시킵니다.
  • 파이프라이닝(Pipelinig)
    • 클라이언트가 여러 개의 요청을 연속적으로 보내고, 서버가 순차적으로 응답 할 수 있게 되었습니다. 이는 지속 커넥션의 효율을 더욱 증가시킵니다.
  • 청크 전송(Chunked Transfer Encoding)
    • 응답의 길이를 미리 알 수 없는 경우에 유용한 "청크 전송 인코딩"방식이 도입되었습니다. 이를 통해 서버는 응답을 여러 개의 청크로 나누어 전송할 수 있고, 클라이언트는 전체 응답을 받기 전에 청크를 처리할 수 있습니다.
  • 호스트 헤더(Host Header)
    • HTTP/1.1에서는 "Host" 헤더가 필수가 되었습니다. 이는 하나의 서버가 여러 도메인을 호스팅하는 가상 호스팅 환경에서 중요합니다. 클라이언트는 요청을 보낼 때 어떤 호스트의 리소스를 요청하는지 명시해야 합니다.
  • 캐시 제어(Cache Control)
    • 캐싱을 더 세밀하게 제어할 수 있는 메커니즘들이 도입되었습니다. 이를 통해 서버와 클라이언트는 리소스의 캐시 가능 여부, 캐시 유효기간 등을 더 정확하게 지정할 수 있습니다.
  • 예외 처리 및 상태 코드 추가
  • 언어, 인코딩 협상(Language and Encoding Negotiations)

여기서 살펴볼 것은 병렬 커넥션, 지속 커넥션과 파이프라이닝을 살펴볼 것이고 이것이 가지고 있는 장단점을 살펴볼 것입니다.

먼저, 기존에 전송 방식을 살펴보면 하나의 커넥션에서 송신자가 요청에 대한 응답을 받기 전까지는 다음 요청을 보낼 수 없습니다. 이것은 회전 지연(latency)을 발생시키게 됩니다.

심지어, TCP Connection을 맺어야 요청들이 2개 이상인 상황에서 하나의 커넥션만 사용할 수 있는 경우에는 이것으로 인한 지연이 높을 것입니다.

이것을 위해서 병렬 커넥션이 등장합니다.

병렬 커넥션은 여러 개의 커넥션을 동시에 맺음으로써 TCP Connection으로 발생하는 지연을 줄여줍니다.

하지만 해당 방식은 다음과 같은 문제점을 가지고 있습니다.

  • "대역폭" 공유
  • 다수의 커넥션은 메모리를 많이 소모
  • 자체적인 성능 문제를 발생시킬 수 있다.

이에 따라 적은 수(대부분 4개)의 병렬 커넥션만 허용합니다.

지속 커넥션의 경우, keep-alive가 가지고 있던 멍청한 프록시 문제라던가 해당 기능을 사용하기 위해서 헤더에 Connection:keep-alive를 추가해야 된다 점이나 확장 기능이였다는 문제점들을 해결하기위해 등장한 것입니다.

이것과 같이 사용할 수 있는 것이 바로 파이프라이닝(Pipelining)입니다.

파이프라이닝은 하나의 지속 커넥션을 통해 여러 요청들을 연속적으로 전송할 수 있도록 해주는 기능입니다.

여기서 중요한 점은, 요청들을 연속적으로 전송하고 나서 이에 대한 응답은 순차적으로 이루어져야 한다는 점입니다.

HTTP 메시지는 순번이 매개져 있지 않아서 응답이 순서 없이 오면 순서에 맞게 정렬시킬 수 있는 방법이 없기 때문입니다.

이로 인해서 발생하는 성능 문제가 'HOL-Blocking'(Head of Line Blocking)입니다.

여기까지 정리를 해보자면,

HTTP/1.1은 요청/응답 지연 문제를 해결하기 위해 병렬 커넥션과 파이프라이닝 기능을 추가하였습니다.
But, 병렬 커넥션은 커넥션 수에 제한이 있고, 파이프라이닝은 'HOL-Blocking'문제가 발생한다는 것을 확인했습니다.

HTTP/2.0

이러한 성능 문제를 개선하기 위해서 HTTP/2.0에 나온 대표적인 기능이 "Multiplexing"입니다.

HTTP/2.0에는 스트림(Stream)이란 개념이 도입되는데 이것은 하나의 커넥션에서 여러 요청과 응답을 처리할 수 있도록 해줍니다.
하나의 커넥션에는 여러 스트림이 생성될 수 있고, 하나의 스트림에는 한 쌍의 요청과 응답을 처리할 수 있습니다.

HTTP/2.0의 대표적인 기능들에 대해서 알아봅시다.

HTTP/2 주요 기능

  1. 바이너리 프로토콜
    • HTTP/2는 이진 프로토콜입니다. 이는 HTTP/1.x의 텍스트 기반 프로토콜과 대조됩니다. 이진 프로토콜은 더 효율적인 구문 분석과 낮은 오버헤드를 제공합니다.
  2. 멀티플렉싱(Multiplexing)
    • HTTP/2에서는 하나의 커넥션을 통해 여러 개의 요청과 응답을 동시에 주고받을 수 있습니다. 이것은 HTTP/1.x에서 볼 수 있는 "헤드 오브 라인 블로킹" 문제를 해결합니다.
  3. 스트림 우선순위(Stream Prioritization)
    • 클라이언트는 요청에 우선순위를 지정할 수 있습니다. 이를 통해 중요한 리소스를 먼저 로드하여 사용자 경험을 향상시킬 수 있습니다.
  4. 서버 푸쉬(Server Push)
    • 서버는 클라이언트의 요청을 기다리지 않고 능동적으로 리소스를 클라이언트에게 보낼 수 있습니다. 이를 통해 클라이언트가 필요로 할 것을 미리 보내 효율성을 높일 수 있습니다.
  5. 헤더 압축(Header Compression)
    • HTTP/2는 HPACK 압축 형식을 사용하여 헤더 데이터를 압축합니다. 이는 HTTP/1.x에서 헤더가 차지하는 대역폭을 줄이는 데 도움이 됩니다.
  6. 보안 연결(HTTPS)
    • HTTP/2는 기술적으로 암호화를 요구하지 않지만, 실제로 대부분의 구현에서는 TLS(Transport Layer Secure)를 통한 보안 연결을 사용합니다.

하나씩 좀 더 구체적으로 정리를 해보도록 하겠습니다.

먼저 기존에는 텍스트 기반 프로토콜이였기 때문에 인코딩을 한다면 ASCII 코드로 변환을 하여 전송을 했습니다. 바이너리 프로토콜의 도입으로 실제 내용보다 더 압축하여 전송이 가능하게 되었습니다.

HTTP/2에서는 모든 메시지가 프레임에 담겨 전송되는데, 프레임의 구조에서 중요한 것은 스트림 식별자와 스트림 페이로드라고 볼 수 있습니다.

모든 스트림은 31비트의 무보호 정수(unsigned integer)로 된 고유한 식별자를 갖는데 이것을 통해 커넥션에서 생성되는 스트림을 구별할 수 있는 것이고 바이너리 데이터는 페이로드에 담긴다고 볼 수 있습니다.

동시에 여럴 개의 스트림을 사용하면 스트림이 블록될 우려가 있는데, 이것은 WINDOW_UPDATE 프레임을 이용한 흐름 제어(flow control)를 통해, 스트림들이 서로 간섭해서 망가지는 것을 막아줍니다.

이렇게 하나의 커넥션 안에서 여러 스트림을 사용할 수 있게 해주면서 Multiplexing 기능을 가능케 해주었습니다.

서버 푸쉬의 필요성의 경우, 예시를 한번 살펴보면 좋을 것 같습니다.

HTML 문서를 요청 받은 서버는 그 HTML 문서가 링크하고 있는 이미지, CSS 파일, 자바스크립트 파일 등의 리소스를 클라이언트에게 푸시할 수 있는 것이다. 이는 클라이언트가 HTML 문서를 파싱해서 필요한 리소스를 다시 요청하여 발생하게 되는 트래픽과 회전 지연을 줄여줍니다.

이 과정에서 PUSH_PROMISE 프레임을 사용하는데 이것을 통해 리소스를 푸시하려는 서버는 클라이언트에게 자원을 푸시할 것임을 알려줍니다.

이것은 하나의 스트림에서 이루어지고, 만약 클라이언트가 원하지 않는다면 RST_STREAM 프레임을 사용해서 거절할 수 있습니다.

이 기능이 동작하는 동안에는 클라이언트는 해당 리소스를 별도로 요청하면 안됩니다.

헤더 압축과 관련해서는 HPACK이라는 특별한 방식으로 헤더를 압축한다고 했고, 여기서 중요한 점이 하나 있는데 헤더와 데이터를 별도의 프레임으로 구분하여 전송한다는 점입니다.

이것은 헤더와 데이터의 전송을 병렬 전송 방식으로 보낼 수 있도록 해줍니다.

HTTP/2만 보더라도 꽤 좋은 기능들을 가지고 있는 것 같다.

그렇다면 HTTP/3은 HTTP/2의 어떠한 단점을 보완하기 위해 나온 것 일까요?

HTTP/2의 단점은 다음과 같습니다.

HTTP/2의 주요 단점

  1. 헤드 오브 라인 블로킹(Head-Of-Line Blocking) in TCP
    • HTTP/2는 TCP 연결 위에서 멀티플렉싱을 사용합니다. 그러나 TCP 자체의 헤드 오브 라인 블로킹 문제로 인해, 하나의 패킷 손실이 전체 연결의 성능 저하를 초래할 수 있습니다. 즉, 여러 스트림이 동일한 TCP 연결을 공유하기 때문에, 한 스트림에서의 문제가 다른 스트림에도 영향을 미칠 수 있습니다.
  2. TCP 연결 지연
    • TCP는 연결을 시작할 때 핸드셰이크가 필요합니다. 이 과정에서 지연이 발생 할 수 있으며, TLS(HTTPS 사용 시)를 함께 사용할 경우 추가적인 지연이 발생합니다.
  3. 네트워크 변경에 취약
    • 모바일 기기가 Wi-Fi에서 모바일 데이터로 네트워크를 전환할 때와 같이 네트워크 환경이 변경되면 TCP 연결이 재설정되어야 합니다. 이는 성능 저하를 초래할 수 있습니다.

좀만 더 정리해보자.

TCP 자체의 헤드 오브 라인 블로킹 문제는 무엇을 말하는 것일까?

  • TCP와 패킷 순서: TCP는 데이터 패킷들의 순서를 유지합니다. 여기서 만약 분실된 패킷이 생길 경우, 해당 패킷이 재전송되고 도착하기 전까지 후속 패킷들의 처리가 지연됩니다.
  • 문제 발생: HTTP/2에서는 하나의 TCP 연결을 통해 여러 개의 요청과 응답이 멀티플렉싱되어 전송됩니다. 이 중 하나의 패킷이 손실되면, 패킷 손실이 포함된 스트림뿐만 아니라 다른 스트림들도 그 후속 패킷들의 처리가 지연될 수 있습니다. 이는 멀티플렉싱의 이점을 상쇄시키는 결과를 가져올 수 있습니다.

네트워크 환경이 변경되면 TCP 재연결?

이것은 네트워크 환경의 변화로 인한 IP 주소 변경 때문입니다.

이러한 문제들을 개선하기 위해 HTTP/3이 등장합니다.

HTTP/3

HTTP/3은 이야기해야 되는 부분이 다소 많을 것 같습니다.

해당 내용은 다음 페이지에서 정리를 해뒀습니다.

탑재된 기능만 정리하자면 다음과 같습니다.

  • UDP 기반의 QUIC 프로토콜 사용
  • 연결 레이턴시(latency) 감소
  • "독립 스트림" 사용
  • Connection ID 사용
  • 보안 강화

참고한 자료

  • HTTP 완벽가이드
profile
개발정리블로그

0개의 댓글