HTTP는 Hypertext Transfer Protocol의 약자로, 초기에 하이퍼 텍스트 문서를 주고 받기 위해 설계된 프로토콜이다. 그래서 최초의 HTTP 버전은 오직 HTML 문서만 주고 받을 수 있었다.
이 글을 통해 HTTP의 역사와 버전에 따른 변경사항을 알아보자.
HTTP/0.9
1991년에 나온 최초의 HTTP 버전으로써, Tim Berners-Lee와 CERN 기관의 연구자들에 의해 개발되었다.
TCP/IP 위에서 동작하며 기본 포트는 80번을 사용한다. GET 요청만 사용할 수 있는 단순한 프로토콜이며 클라이언트가 서버에 요청하면 서버는 HTML 메시지를 응답한 뒤 종료한다.
위의 문장을 조금 더 자세히 설명하면 아래와 같다.
TCP/IP 위에서 동작하며 기본 포트는 80번을 사용한다. 클라이언트 요청은 GET 요청만 사용할 수 있는 단일한 ASCII 문자열이며, 클라이언트 요청은 캐리지 리턴(CR, \r)을 통해 끝난다. 클라이언트 요청에 따른 서버 응답은 ASCII 문자열이며, 서버의 응답은 하나의 HTML이다. 문서 전송이 완료되면 연결이 종료된다.
HTTP/1.0
인터넷 인프라가 진화 및 상호 영향을 주며 발전하면서 HTTP 0.9를 사용하던 웹 서버들은 0.9 버전에 명시되지 않은 자체 기능들을 구현해 사용했었다. 이러한 자체 기능들을 모아 문서화해 발표한 버전이 1.0 버전이다.
헤더의 추가
헤더는 해당 메시지의 정보를 담는 역활을 하며 해당 메시지의 의미를 파악할 수 있다. 버전 정보(HTTP/1.0), 상태 코드(200 OK), 문서 타입(Content-Type: text/html)이 추가되어 메시지를 받았는지, 받은 문서의 타입 등의 정보를 확인하고 이에 맞게 대응할 수 있게 되었습니다.
HTTP/1.1
HTTP/1.1은 HTTP/1.0과 큰 맥락은 비슷하지만 일부 기능이 변경된 버전이 릴리스되었다.
1.0 버전은 매 요청마다 새로운 연결을 맺어야 하는 방식이여서 컴퓨터와 응답 컴퓨터가 데이터 통신에는 한번 데이터를 주고 받으면 연결을 해제하고 다시 통신할 때 다시 새로운 연결을 해야했다.
이때 발생하는 문제는 동일한 컴퓨터 사이에서 여러개의 데이터를 요청할 때에도 매 요청마다 새로운 연결을 계속해서 만들어야 한다는 점이다. 이게 왜 문제가 되냐를 알고 가야한다.
연결을 만들 경우 TCP에서 3-way-handshake가 이뤄지는데, 한번의 3-way-handshake의 동작 시간이 짧지가 않다는 것이다..... 이러한 동작이 여러번 반복해서 동작한다면 데이터 통신 속도가 느려지게 된다.
물론 초창기 웹에서는 통신하는 데이터의 양과 크기가 적기 때문에 큰 문제는 되지 않았지만, 요즘의 웹에서 통신하는 데이터의 양과 크기는 초창기 웹가 비교할 수 없을 정도로 많아지고 커졌기 때문에 1.0 버전의 통신 방법은 문제가 있음을 유추할 수 있다....
이러한 문제점을 해결하고자 HTTP/1.1에서는 효율적으로 통신 속도를 개선했다.
두 가지 개선 사항이 있었다.
Persistent Connections
Persistent Connections는 한번 TCP 연결을 맺으면 끊기지 않고 계속 유지할 수 있게 해주는 기능이다.
클라이언트와 서버의 TCP 연결한 뒤 요청에 대한 응답이 전달되면 TCP 연결을 끊지 않는다라는 약속으로 동일한 헤더를 HTTP 응답에 포함한다. 물론 TCP 연결을 끊어야 하는 상황에서는 기존에 Connection 헤더로 전달된 keep-alice를 close로 바꿔주며 TCP 연결을 끊을 수 있다.
Pipelining
Http 요청들을 연속적으로 발생하며 순차적으로 동작한다. 기존 HTTP/1.0 에서는 이전 요청에 대한 응답이 도착해야지 다음 요청을 보낼 수 있었다. 이는 이전 응답이 늦게 도착하는 경우 공백 시간이 발생할 수 있다는 문제가 있었다.
이러한 문제를 해결하기 위해 HTTP/1.1의 Pipelining을 적용해 다수의 요청이 서버 소켓에 작성된 후, 브라우저는 각 요청에 대한 응답 처리를 뒤로 미루는 방법을 적용했다. 이는 여러개의 요청을 하나의 TCP/IP 패키지로 연속적으로 Packing해 요청을 전달한다.
이렇게 여러 요청에 대한 응답을 기다리지 않고 여러 요청을 전달하고 응답을 한번에 받음으로 통신의 요청 및 응답 동작의 속도를 높일 수 있었다.
하지만 이러한 파이프라이닝 기술은 아래와 같은 이유로 인해 모던 브라우저에서는 사용하지 않는다.
- 파이브라이닝을 지원하지 않는 프록시 서버가 존재
- 제대로된 파이프라이닝을 서버에 구현하기 어려움
- 이전 요청에 대한 응답을 보내기 전에 다음 요청에 대한 응답을 보낼 준비가 되었을 때, 현재 응답을 보내지 않고 이전 응답을 기다리는 HOL(Head-Of-Line Blocking) 문제가 있다.
SPDY
Google에서 SPDY(스피디) 라는 새로운 실험용 프로토콜을 발표했다.
SPDY는 HTTP와는 별개의 프로토콜이 아닌 TLS 위에서 동작하는 프로토콜로써, HTTP 요청을 보내면 이를 SPDY 요청으로 변환해 서버로 전달한뒤 응답을 다시 HTTP로 변환하는 방식으로 동작한다. HTTP/1.1 까지 존재했던 문제점을 해결하기 위해 적용한 기술들은 다음과 같다.
- Multiplexed Streams: 하나의 TCP 연결을 통해 요청 및 응답을 독립적인 스트림으로 묶어 처리하며, 한 스트림이 진행중 이여도 다른 스트림이 끼어들 수 있다.
- Request Prioritization: 각 스트림의 우선순위를 설정해 우선순위가 낮은 데이터를 전송하다 우선순위가 높은 데이터가 끼어들어 더 빨리 전달할 수 있도록 한다.
- Binary Protocol: 프레임을 텍스트가 아닌 바이너리로 구성해 파싱을 빠르게 할 수 있으며 오류 발생 가능성을 낮춘다.
- Header Compression: 헤더 압축을 통해 요청 데이터의 크기를 더 작게 할 수 있다.
- Server Push: 서버 푸시를 통해 클라이언트가 요청하지 않은 컨텐츠도 서버에서 미리 전송해 RTT(Round Trip Time)을 줄일 수 있다.
이러한 프로토콜을 유심히 관찰하던 HTTP 개발자는 SPDY 기반의 새로운 HTTP 버전을 만들기 위해 SPYD 개발자들과 협업을 했다. 그 결과가 바로 다음에 소개할 HTTP/2 버전이다.
HTTP/2
앞서 설명한 HTTP/1.1의 문제점인 HOL 문제를 기억할 것입니다. 이전 요청에 대한 응답으로 인해 다음 요청에 대한 응답을 전달할 수 없는 문제가 HTTP/1.1에는 존재했습니다.
하지만 HTTP/2 에서는 이전 요청에 대한 응답을 기다리지 않고 다음 응답을 전달할 수 있도록 모든 요청과 응답을 병렬적으로 처리했습니다.
이진 프레이밍 레이어 (Binary Framing Layer)
HTTP/1.1 까지는 메시지라는 텍스트 프로토콜 단위로 요청과 응답이 구성되었습니다. 이 메시지에 요청과 응답에 필요한 정보가 저장되며 ASCII로 인코딩하여 표현되었습니다.
하지만 HTTP/2 에서는 이진 프레이밍 레이어를 통해 이진 형태로 캡슐화된 단위로 데이터를 주고받습니다.
이외에도 스트림과 프레임이라는 단위가 추가되었습니다.
스트림은 클라이언트와 서버 사이의 연결을 이용해 양방향으로 메시지를 주고받는 통로입니다. 쉽게 이야기하여 한 연결의 가상 채널입니다.
메시지는 HTTP/1.1에서의 요청 및 응답의 단위이며 다수의 프레임으로 구성됩니다.
프레임은 HTTP/2 통신의 가장 작은 단위이며 HTTP 헤더, 페이로드와 같은 데이터가 저장됩니다.
HTTP/2 에서는 다수의 프레임이 모여 하나의 메시지가 되고, 여러 메시지가 모여 하나의 스트림이 되는 구조로 통신이 동작합니다.
HTTP/1.1 까지의 요청 및 응답은 메시지 단위로 구분되어 있었지만, HTTP/2에서는 스트림 단위를 통해 요청 및 응답이 하나의 단위로 묶이는 구조를 갖습니다.
또한 HTTP/1.1에서는 연결을 재사용할 수 있었지만, HTTP/2의 스트림은 재사용되지 않습니다.
요청 및 응답을 전달할 때 스트림 번호를 각 프레임에 매핑하며 클라이언트는 매핑된 스트림 번호를 통해 해당 스트림이 어떤 요청에 대한 응답인지 확인할 수 있습니다.
HTTP/2 스트림은 요청-응답 사이클에 의해 동작하며 일회성으로 매핑되어 있는 번호를 이용해 요청에 대한 응답을 구분하기 위해 매핑한 번호를 일회성으로 사용합니다. 이러한 이유로 인해 HTTP/2에서 스트림은 재사용하지 않습니다.
'CS' 카테고리의 다른 글
크루스칼 알고리즘(Kruskal Algorithm) (0) | 2024.08.12 |
---|---|
Tree 자료구조 (0) | 2024.08.07 |
배열 Array (0) | 2024.07.19 |
Hash Table (0) | 2024.07.12 |
자료구조 / 힙 Heap (0) | 2024.03.08 |