본문 바로가기

CS 백엔드/네트워크

HTTP/0.9, 1.0, HTTP/1.1, HTTP/2, 그리고 QUIC

0. 들어가며

HTTP는 OSI 7계층에서 응용 계층에 속해있다. 그렇기 때문에 아래 단계인 전송 계층에 대해서 이해가 필요하다.

전송 계층은 클라이언트가 서버에 신뢰할 수 있는 데이터를 전송하기 위해 필요하다. 전송 계층 아래 단계 물리, 데이터링크, 네트워크 계층만으로 목적지에 데이터를 보낼 수 있디만, 중간에 데이터가 손사오디거나 유실되더라도 이들 계층에서는 아무것도 해주지 않는다. 즉, 데이터가 제대로 전달 되었는지의 역할은 전송 계층에서 해주는 것이다.

 

 

1. HTTP/0.9

: GET 메서드

HTTP의 초기 버전은 따로 없었다. 차후에 다른 버전과 구별을 하기 위해 버전 번호를 붙이기 시작할 때가 HTTP/0.9버전 부터이다.
0.9의 요청은 단일 라인으로 구성되며 리소스에 대한 경로로 가능한 메서드는 GET 메서드가 유일했다. 또한 요청과 응답이 매우 단순하다.

<요청>
GET /mypage.html​

<응답>
<HTML> A very simple HTML page </HTML>​


위처럼 요청과 응답이 매우 간단하며, HTTP 헤더가 따로 없었고 HTTP 파일만 전송될 수 있다.

 

 

2. HTTP/1.0

: 헤더의 등장으로 이미지, 영상 등의 데이터 전송이 가능
헤더라는 것에 여러 정보를 포함시킬 수 있게 되었다.
  • 버전 정보인 HTTP/1.0이 GET 라인에 붙어서 전송되었다.
  • 상태 코드 또한 응답의 시작 부분에 붙어 전송되어, 브라우저가 요청에 대한 성공과 실패를 알 수 있고 그 결과에 대한 동작을 할 수 있게 되었다.
  • HTTP 헤더 개념은 요청과 응답 모두를 위해 도입되어, 유연하고 확장 가능하게 되었다.
  • 새로운 HTTP 헤더의 도움으로, HTML 파일 외에 다른 문서도 전송이 가능. (Content-Type 덕분)
  • Connection: keep-alive 단기 커넥션 유지가 가능했지만 기본 디폴트도 아니었고, 이 헤더를 이해 못하는 프록시들이 있어서 멍청한 프록시라는 문제점이 발생 (HTTP/1.1에서는 지속 커넥션을 통해 개선)
# 요청 메세지
GET /mypage.html HTTP/1.0                		# start-line
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)   		# 요청 해더


# 응답 메세지
200 OK --> 상태 코드
Date: Tue, 15 Nov 1994 08:12:31 GMT			# 일반(General) 헤더
Server: CERN/3.0 libwww/2.17				# 응답 헤더
Content-Type: text/html					# 앤터티/개체 해더(보통 응답 헤어에 포함)

<HTML>							# 응답된 데이터
A page with an image
  <IMG SRC="/myimage.gif">
</HTML>

< 이미지 파일 요청 >

# 요청 메세지
GET /myimage.gif HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)


# 응답 메세지
200 OK
Date: Tue, 15 Nov 1994 08:12:32 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/gif

(image content)

1) 1.0 버전의 특징

아래와 같이 커넥션 하나에 요청(Request) & 응답(Response) 1개에 해당한다.
이러한 특징은 하나의 요청과 응답을 하기 위해서는 당연히 매번 새로운 연결을 해야한다. 이는 곧 성능 저하를 불러일으킬 수 있다.
또한 서버의 부하 비용이 증가하는 큰 단점들이 있다.

 

3. HTTP/1.1

: 현재 표준 프로토콜이며 많은 개선 사항들이 있는 버전이다.

1) 커넥션(SYN, ACK, FIN의 handshake) 재사용

  • HTTP/1.0에서는 요청이 1개 보내질 때마다 커넥션이 1개 매번 새롭게 생성(Short-lived connections)되었고 응답이 도착한 이후에 연결을 닫는 형태로 유지되었다. HTTP/1.1에서는 Persistent Connection을 통해 지정한 timeout동안 [요청과 응답] 여러 개를 받을 수 있도록 커넥션을 닫지 않고 재사용을 할 수 있게 하였다.
  • 연결 - [요청/응답] - [요청/응답] - [요청/응답] - 종료

 

2) 파이프라이닝

  • 하나의 Connection에서 요청에 대한 응답을 기다리지 않고 요청을 연속적으로 보내는 기능.
  • 첫번째 요청에 대한 응답을 기다리지 않고 두번째, 세번째 요청을 연속적으로 보내 그 순서에 맞춰 응답을 받는 방식으로 지연 시간을 줄이는 방법을 도입하였다. 
  • 연결 - [요청1, 요청2, 요청3] - [응답1, 응답2, 응답3] - 종료

 

3) 파이프 라이닝 문제점  ->  Head of Line Blocking

Head of Line(HOL) Blocking은 파이프라이닝이 응답 순서는 보장해야 하기 때문에, 첫번째 요청이 서버에서 처리시간이 너무 오래 걸리면, 두 세번째 요청에 대한 응답도 마냥 기다려야 하는 비효율이 발생한다. CSS 리소스에 대한 요청이 먼저 처리된다고 하더라도 HTML 요청이 먼저 도착했기 떄문에 HTML 응답이 전송될 때까지 CSS응답은 block된다.

 

4) Domain Sharding(도메인 샤딩)

Head of Line(HOL) Blocking를 해결하기 위해 등장하였다.

도메인명을 여러개 설정해서 같은 서버에 정적 파일(이미지, CSS, JS)을 병렬로 요청하면, 여러개의 커넥션을 맺을 수 있게 된다. 이렇게 되면 리소스를 병렬적으로 동시에 받을 수 있게 된다.

그러나! 브라우저별로 도메인 커넥션 개수 제한도 있고 근본적인 해결책이 되지 못한다.

 

5) 무거운 Headers 구조

HTTP/1.1의 헤더에는 많은 정보들이 저장되어 있다.
매 요청시마다 중복된 Header 값을 전송하게 되어 불필요한 Header 값이 커지게 되는 단점이 발생한다.

 

 

4. HTTP/2.0

: HTTP/1.x에 비해 더 적은 TCP 연결을 사용, 네트워크에 더 친화적, 성능 향상과 확장에 초점을 맞추었다.

(1) 바이너리 메시지 프레이밍 계층을 사용하여 보다 효율적인 메시지 처리를 가능.
(2) 하나의 연결(단일 TCP Connection)에서 요청 및 응답 Multiplexing(다중화)을 허용하여 네트워크 리소스를 보다 효율적으로 사용하고 지연 시간을 줄임.
(3) 요청의 우선순위 지정을 허용함으로써 더 중요한 요청은 응답이 더 빨리 완료되도록 하여 성능을 더욱 개선.
(4) 서버 푸시로 클라이언트가 명시적으로 요청하지 않아도 서버가 추가적인 리소스를 미리 클라이언트로 보냄.
(5) 헤더 필드 압축을 도입.

HTTP/1.1, HTTP/2.0 버전의 속도 비교 영상
https://www.youtube.com/watch?v=nqgDMXDH9vU

 

1) HTTP 메시지 전송 방식의 변화 - 바이너리 프레이밍 계층

  • 바이너리(이진) 프레이밍 계층이 생겼다. 이제 텍스트 형식의 메시지를 보내는 것이 아니라, 프레임(frame)이라는 단위로 텍스트를 바이너리로 변환해서 전송된다.
  • 줄바꿈으로 구분되는 일반 텍스트 HTTP/1.x 프로토콜과 달리, 모든 HTTP/2 통신은 더 작은 메시지와 프레임으로 분할되며, 각각은 바이너리 형식으로 인코딩된다.
  • 따라서 클라이언트와 서버는 서로를 이해하기 위해 새 바이너리 인코딩 메커니즘을 사용해야 하며, HTTP/1.x 클라이언트는 HTTP/2 전용 서버를 이해하지 못하며 그 반대도 마찬가지이다.
  • 바이너리로 변환해서 전송하므로, 파싱 및 전송 속도가 빠르고 네트워크 오류 발생 가능성이 적어진다. 네트워크 대기 시간 감소 및 처리량 향상, 응답 분할 공격과 같은 HTTP/1.x의 텍스트 특성과 관련 보안 문제를 제거한다.
    • 아무래도 컴퓨터는 텍스트 기반의 데이터보다 바이너리 기반의 데이터를 처리하는데 있어서 더 빠르기 때문에 텍스트를 바이너리로 변환하는 작업을 거치지 않고 디코딩만으로 데이터를 받을 수 있다. 그래서 속도적인 방면에서 큰 이점을 가져올 수 있다.

 

클라이언트와 서버가 연결된 하나의 TCP 커넥션 안에 스트림이라는 데이터 양방향 흐름이라는게 있다. 이 안에 프레임이라는 단위가 들어가서 요청 및 응답 메시지가 되는 것이다.
HTTP/1.1에서는 요청과 응답이 메시지라는 단위로 완벽하게 구분되어 있었으나, HTTP/2.0에서는 Stream이라는 단위를 통해 요청와 응답이 묶일 수 있는 구조가 만들어졌다고 볼 수 있다.

아래는 2.0의 용어에 대한 설명이다.

2) 스트림, 메시지 및 프레임

  • 스트림 : TCP 커넥션 안에서 전달되는 바이트의 양방향 흐름이며, 하나 이상의 메시지가 전달된다.
  • 프레임 : HTTP/2.0에서 통신 최소 단위이며, 각 최소 단위에는 하나의 Headers frame 또는 data frame를 포함한다.
  • 프레임 헤더 : 특정 스트림에 속하는 메시지에 매핑된다.
  • 메시지 : 각 메시지는 하나의 논리적 HTTP 메시지(요청 또는 응답)이며, 다수의 프레임으로 이루어져있다.
    • 즉, frame이 여러개가 모여 message가 되고, 요청 및 응답 message가 모여 stream이 되는 구조이다.
      • 모든 통신은 단일 TCP 연결을 통해 수행되며 전달될 수 있는 양방향 스트림의 수는 제한이 없다.
      • 각 스트림에는 양방향 메시지 전달에 사용되는 고유 식별자 우선순위 정보가 있다.

위 그림은 클라이언트 - 서버 간 하나의 TCP 연결 상태에서의 N개의 스트림 구성을 보여준다.

Stream 1은 [요청 메시지 하나/응답 메시지 하나]가 있고, 요청 메시지는 하나의 Header 프레임(GET 요청으로 Data 부분이 존재 하지 않음)으로 구성되어 있고, 응답 메시지는 각각 하나의 헤더 프레임, 데이터 프레임으로 구성되어 있다. Stream N의 그림을 보면, 복수개의 요청, 복수개의 응답 프레임이 하나의 스트림 안에 존재한다. (다중 요청/응답 가능)

 

3) 요청 및 응답 다중화(Multiplexing)

HTTP/1.x에서 성능 개선을 위해 클라이언트가 병렬 요청을 수행하려는 경우, 여러 TCP 연결이 사용되어야 했다. (위에서 설명한 domain sharding) 이 동작은 연결당 한번에 하나의 응답만 전달되도록 보장하고, 기본 TCP 연결의 비효율적인 사용을 초래했다.

 

HTTP/2의 새 바이너리 프레이밍 계층은 이러한 제한을 없애주고 전체 요청 및 응답 다중화를 지원한다. 이를 위해 클라이언트와 서버가 HTTP 메시지를 독립된 프레임으로 세분화하고, 이 프레임을 끼워넣은(인터리빙)다음, 다른 쪽에서 다시 조립하도록 허용한다.

그래서 어떤 순서로 프레임이 도착하든 기다리지 않고 조립 하면 되므로, Head of Line Blocking이 해결된 것이다.

위 스냅샷은 동일한 연결(하나의 TCP Connection) 내의 여러 스트림을 캡쳐 한건데, 클라이언트는 DATA 프레임(스트림 5)을 서버로 전송 중인 반면, 서버는 스트림 1과 스트림 3의 인터리빙(끼워넣기)된 프레임을 클라이언트로 전송 중이다. 따라서 하나의 커넥션 3개의 병렬 스트림이 존재한다. HTTP 메시지를 독립된 프레임으로 세분화하고 이 프레임을 인터리빙한 다음, 다른 쪽에서 다시 조립하는 기능은 HTTP/2에서 가장 중요한 기능 향상이다.

  • 여러 요청을 하나도 차단하지 않고 병렬로 인터리빙 가능
  • 여러 응답을 하나도 차단하지 않고 병렬로 인터리빙 가능
  • 단일 연결을 사용하여 여러 요청과 응답을 병렬로 전달

 

4) 스트림 우선순위 지정(stream Priritization)

리소스(frame)간 전송 우선 순위를 설정이 가능하게 되었다. 각 스트림에는 1~256 사이의 정수 가중치가 할당될 수 있어스트림에 우선순위를 부여할 수 있다. 그럼 서버는 우선순위가 높은 응답 클라이언트에 먼저 전달되도록 대역폭을 할당한다.

 

5) 서버 푸시

서버가 단일 클라이언트 요청에 대해 여러 응답을 보낼 수 있다는 것이다.. 즉, 서버는 원래 요청에 응답할 뿐만 아니라 클라이언트가 명시적으로 요청하지 않아도 서버가 추가적인 리소스를 클라이언트에 푸시할 수 있다.

서버가 생각하기에 클라이언트한테 /page.html을 받으면, 서버는 어떤 리소스가 클라이언트에 또 필요한지 이미 알고 있어서 /script.js와 /style.css를 미리 보내버리는 기능이다.

 

6) 헤더 압축(Header Compression)

중복되는 헤더의 크기를 줄여 페이지 로드 시간을 줄이는 기술이다.

Header 정보를 압축하기 위해 Static/Dynamic Header Table과 Huffman Encoding의 두 가지 기술을 사용한다.

위 그림처럼 클라이언트가 두 번의 요청을 보낸다고 가정하면 HTTP/1.x의 경우 두 개의 요청 Header에 중복값이 존재해도 그냥 중복 전송한다. 하지만 HTTP/2에선 Header에 중복값이 존재하는 경우 Static/Dynamic Header Table 개념을 사용하여 중복 Header를 검출하고 중복된 Header index값만 전송하고 중복되지 않은 Header정보의 값은 Huffman Encoding기법으로 인코딩 처리하여 전송한다.

 

 

5. QUIC

: UDP 기반의 통신 프로토콜, TCP 자체의 HOL Blocking 해결

QUIC(퀵)
은 구글에서 설계된 범용 목적의 전송 계층 통신 프로토콜이다. QUIC는 구글 크롬에서부터 구글 관련 제품 대부분의 기본 프로토콜로, TCP의 성능을 개선하고자 UDP기반으로 만들어진 프로토콜이다.

<보충 설명>
UDP는 처리 속도가 빠른 반면 데이터의 신뢰성 확보가 어렵지만, QUIC 계층을 추가하여 TCP만큼 신뢰성을 제공할 수 있게 하였다.
위의 의미는 TCP는 신뢰성이 보장되지만 속도가 느린 단점을 가지고 있다. TCP는 기본적인 구조가 굉장히 복잡하기 때문에 성능 개선을 하기위한 제약이 커서 구글에서는 속도는 빠르지만 신뢰성이 보장되지 않는 UDP 프로토콜을 선택했다. 그 이유는 TCP 보다 구조가 간단하고 성능을 개선시킬 수 있는 가능성이 더 크기 때문이다.

 

1) 전송 속도 향상, Connection UUID로 서버와 연결 수립

QUIC 이론적으로 전송 왕복 시간(RTT, Round-Trip Time)이 0이다. 첫 연결에서 설정에 필요한 정보와 함께 데이터를 함께 보낸다. 연결을 성공하면 설정을 캐싱해서 다음 연결 때, handshake 필요없이 바로 데이터 전송이 가능하도록 되었다. QUIC Connection UUID라는 고유한 패킷 식별자를 사용하므로 한번이라도 클라이언트와 서버가 데이터 전송을 수행했다면 이동중 로밍이 발생하거나 심지어 IP 주소가 변경되어도 커넥션을 다시 수립할 필요가 없다.

 

2) 보안성 향상

(1) TLS 적용

QUIC은 TLS 암호화를 기본적으로 적용하고 있다. 과거 SPDY와 마찬가지로 구글에서 설계한 네트워크 프로토콜은 기본적으로 암호화를 적용하고 있고, 서버의 포트도 디폴트가 443 UDP 포트를 사용하고 있다.

 

(2) IP Spoofing / Replay Attack 방지

QUIC에서는 필요에 따라 Source Address Token을 발급하여 출발지 IP를 변조 및 재생공격에 대한 검증을 수행한다. 마치 TCP 통신에서 Sequence Number를 이용하여 신뢰 관계를 맺은 클라이언트인지 검증하는 것과 같은 기능을 수행한다.

 

 

3) '독립 스트림'으로 더향상된 멀티플렉싱(multiplexing) - TCP 자체의 HOL Blocking 방지

HTTP/2에서도 멀티플렉싱 기능을 제공하기는 했다. 그러나 TCP 자체에도 Head of Line Blocking 이슈가 있다.

만약 TCP 통신에서는 다수의 스트림을 하나의 TCP Connection으로 전송 중에 유실된 패킷이 발생하면 다른 스트림의 데이터도 유실된 패킷이 재전송 될 때까지 대기상태(Block)가 되지만, QUIC에서는 유실된 패킷이 속한 데이터를 제외한 다른 데이터는 별도의 Block없이 지속적으로 처리 할 수 있도록 설계되었다.

위 그림을 보면, QUIC은 하나의 UDP Connection 안에서 데이터를 동시에 전송하는 스트림을 독립적으로 다중화하여 스트림 중 하나의 데이터가 손실이 발생했을 때, 다른 스트림의 데이터 전달을 차단하지 않아 HoL Blocking을 방지할 수 있다.

 

 

5) HTTP/3 UDP 기반 QUIC 프로토콜을 사용

HTTP/1.1, HTTP/2와 다르게 HTTP/3 UDP 기반의 QUIC 프로토콜을 사용한다.

사실 HTTP/3는 처음에는 HTTP-over-QUIC이라는 이름을 가지고 있었는데, IETF(Internet Engineering Task Force) 내 HTTP 작업 그룹과 QUIC 작업 그룹의 의장인 마크 노팅엄이 이 프로토콜의 이름을 HTTP/3로 변경할 것을 제안했고, 2018년 11월에 이 제안이 통과되어 HTTP-over-QUIC이라는 이름에서 HTTP/3으로 변경되게 되었다.

 

 

 

[참고]

https://www.youtube.com/watch?v=xcrjamphIp4 

https://velog.io/@minu/HTTP1.0-HTTP1.1-HTTP2-and-QUIC

https://bentist.tistory.com/36

 

 

 

'CS 백엔드 > 네트워크' 카테고리의 다른 글

[네트워크] 네트워크란 무엇인가?  (0) 2023.01.08
[네트워크] Cache  (0) 2022.11.09
Forward Proxy, Reverse Proxy  (0) 2022.10.25
HTTP  (0) 2022.10.23
도메인과 DNS - 이론  (0) 2022.10.20