
멀티플렉싱: 하나의 연결(Connection) 위에서 여러 작업을 동시에 흘려보내는 것(HOL Blocking 문제를 해결)
-> 하나의 TCP 연결 위에서 여러 HTTP 요청/응답 스트림을 동시에 처리
QUIC은 UDP 기반으로 구현되며 TCP가 하던 재전송, 순서 보장, 혼잡 제어를 자체적으로 수행한다. 그리고 스트림 단위로 독립적으로 동작하기 때문에 Stream A에서 패킷 손실이 발생해도 Stream B는 계속 처리할 수 있다.
네트워크 애플리케이션 개발의 중심은 다른 위치의 종단 시스템에서 동작하고 네트워크를 통해 서로 통신하는 프로그램을 작성하는 것이다.
예를 들어, 웹 애플리케이션에는 서로 통신하는 서버(웹 서버 프로그램)와 클라이언트(사용자 호스트에서 실행되는 브라우저 프로그램)로 구별되는 두 가지 프로그램이 있다.
중요한 것은 우리가 라우터나 링크 계층 스위치처럼 네트워크 코어 장비에서 실행되는 소프트웨어까지 작성할 필요는 없다는 점이다.
(그렇게 하고 싶더라도 네트워크 코어 장비는 애플리케이션 계층에서 기능하지 않기 때문에 그렇게 할 수 없다.)
애플리케이션 구조는 네트워크 구조와 분명히 다르다.
애플리케이션 개발자 관점에서 네트워크 구조는 고정되어 있고, 해당 애플리케이션의 특정 서비스 집합을 제공한다.
반면, 애플리케이션 구조는 애플리케이션 개발자가 설계하며, 애플리케이션이 여러 종단 시스템에서 어떻게 조직되어야 하는지를 알려준다.
peer라는 간헐적으로 연결된 호스트 쌍이 서로 직접 통신하게 한다.실제 통신하는 것은 프로그램이 아니라, 실행되고 있는 프로그램인 프로세스이다.
2개의 종단 시스템에서 프로세스는 컴퓨터 네트워크를 통한 메시지 교환으로 서로 통신한다.
송신 프로세스는 메시지를 만들어서 보내고 수신 프로세스는 메시지를 받고 역으로 메시지를 보냄으로써 응답한다.
네트워크 애플리케이션은 네트워크에서 서로 메시지를 보내는 두 프로세스로 구성된다.
클라이언트와 서버 프로세스를 다음과 같이 정의한다.
💡 두 프로세스 간의 통신 세션에서 통신을 초기화(다른 프로세스와 세션을 시작하려고 접속을 초기화)하는 프로세스를
클라이언트(client)라 하고, 세션을 시작하기 위해 접속을 기다리는 프로세스를서버(server)라고 한다.
간단히 말하면, 요청을 보내는 쪽의 프로세스를 보통 클라이언트라고 하고, 요청을 받는 쪽을 서버라고 한다.
당연히 P2P 구조에서 봤듯이, 클라이언트도 서버 프로세스가 될 수 있고, 서버도 클라이언트 프로세스가 될 수 있다.
프로세스는
소켓(socket)을 통해 네트워크로 메시지를 보내고 받는다.
네트워크에서 프로세스를 집이라 한다면, 소켓은 마치 문과 같은 존재이다.
위 그림에 보이듯이, 소켓은 호스트의 애플리케이션 계층과 트랜스포트 계층간의 인터페이스다.
네트워크 애플리케이션이 인터넷에 만든 프로그래밍 인터페이스이므로, 애플리케이션과 네트워크 사이의 API라고도 한다.
애플리케이션 개발자는 소켓의 애플리케이션 계층에 대한 모든 통제권을 갖지만, 소켓의 트랜스포트 계층에 대한 통제권은 거의 갖지 못한다.
애플리케이션 개발자의 트랜스포트 계층에 대한 통제
프로세스가 다른 수행되고 있는 다른 패킷으로 프로세스를 보내기 위해서는 수신 프로세스가 주소를 갖고 있어야 한다.
수신 프로세스를 식별하기 위해서는 두 가지 정보가 필요하다.
송신 측의 애플리케이션은 소켓을 통해 메시지를 보내고,
트랜스포트 프로토콜은 네트워크를 통해 그 메시지를 수신 프로세스의 소켓으로 이동시킬 책임이 있다.
인터넷을 포함한 많은 네트워크는 트랜스포트 프로토콜을 하나 이상 제공한다.
트랜스포트 프로토콜이 그것을 이용하는 애플리케이션에게 제공할 수 있는 4가지 서비스를 알아보자.
1장에서 보았듯이, 패킷들은 컴퓨터 네트워크 내에서 손실될 수 있다.
이러한 데이터 손실은 위험한 결과를 초래할 수 있다.
만약 프로토콜이 보장된 데이터 전송 서비스를 제공한다면 신뢰적 데이터 전송이라고 한다.
트랜스포트 프로토콜이 이 서비스를 제공할 때, 송신 프로세스는 데이터를 소켓으로 보내고 그 데이터가 오류 없이 수신 프로세스에 도착할 것이라는 확신을 갖는다.
트랜스포트 프로토콜이 이 서비스를 제공하지 않을 때 송신 프로세스가 보낸 데이터는 전혀 도착하지 않을 수 있다.
이러한 애플리케이션을 손실 허용 애플리케이션(실시간 비디오/오디오 애플리케이션 등이 대표적)이라고 한다.
다른 세션들이 네트워크 경로를 따라 대역폭을 공유하고, 이 세션들이 생겼다 없어졌다 하기 때문에 가용한 처리율은 시간에 따라 변한다.
트랜스포트 프로토콜은 어느 명시된 속도에서 보장된 가용 처리율을 제공한다.
처리율 요구사항을 갖는 애플리케이션은 대역폭 민감 애플리케이션이라 하고, 현존하는 많은 멀티미디어 애플리케이션은 대역폭에 민감하다.
(너무 처리율이 낮으면 전화같은 서비스가 불가능하다.)
반대로 요구사항이 없는 애플리케이션을 탄력적 애플리케이션(elastic apps)이라고 한다.
트랜스포트 프로토콜은 시간 보장을 제공할 수 있다.
예를 들어, 송신자가 소켓으로 내보내는 모든 비트가 수신자의 소켓에 100ms 내에 도착하게 할 수 있다.
실시간 애플리케이션에 주로 사용된다.
송신 호스트에서 트랜스포트 프로토콜은 모든 데이터를 암호화할 수 있고, 수신 호스트에서 트랜스포트 프로토콜은 모두 해독할 수 있다.
보통 TCP를 애플리케이션 계층에서 강화하여 TLS로 보안 서비스를 제공한다. (자세한 내용은 8장에서 다룬다.)
TLS는 TCP 위에서 동작하면서 TCP에 보안 기능을 추가하는 프로토콜
TCP 전송 프로토콜은 다음 세 가지 서비스를 제공한다.
애플리케이션 계층 메시지를 전송하기 전에 TCP는 클라이언트와 서버가 서로 전송 제어 정보를 교환하게 한다.
이 핸드 셰이킹(handshaking) 과정이 클라이언트와 서버에 패킷이 곧 도달할테니 준비하라고 알려주는 역할을 한다.
핸드셰이킹 단계를 지나면, TCP 연결이 두 프로세스의 소켓 사이에 존재한다고 말한다.
이 연결은 두 프로세스가 서로에게 동시에 메시지를 보낼 수 있기에 전이중 연결이라고 한다. (3장에서 더 자세히 다룬다.)
통신 프로세스는 모든 데이터를 오류 없이 올바른 순서로 전달하기 위해 TCP에 의존한다.
TCP는 애플리케이션의 한 쪽이 바이트 스트림을 소켓으로 전달하면, 그 바이트 스트림이 손실되거나 중복되지 않게 수신 소켓으로 전달한다.
네트워크가 혼잡 상태에 이르면 프로세스의 속도를 낮추는 방법 (또한, 3장에서 자세히 다룬다.)
UDP는 최소의 서비스 모델을 가진 간단한 전송 프로토콜이다.
UDP는 비연결형으로 핸드셰이킹 과정이 없고, 비신뢰적인 데이터 전송 서비스를 제공하여 데이터가 전달되는 것을 보장하지 않는다.
UDP는 또한 혼잡 제어 방식을 포함하지 않아 프로세스의 속도 저하 없이 네트워크를 이용할 수 있다.
그러나 혼잡으로 인해 종단 간 처리율이 낮아져서 속도가 오히려 더 낮아질 수 있다.
TCP와 UDP는 처리율 혹은 시간 보장 서비스를 제공하지 않는다.
시간 민감 애플리케이션 같은 경우에는 이러한 처리율 및 시간 지연에 잘 대처할 수 있도록 설계되어 있다.
그러나 지연이 과도할 때는 보장이 없기 때문에 한계가 있다.
💡 애플리케이션 계층 프로토콜은 다른 종단 시스템에서 실행되는 애플리케이션의 프로세스가 서로 메시지를 보내는 방법을 정의한다.
이는 다음과 같은 내용을 정의한다.
문법(syntax)의미(semantics)여러 애플리케이션 계층 프로토콜은 RFC에 명시되어 있어 공중 도메인에서 찾을 수 있다.
예를 들어, 만약 브라우저 개발자가 HTTP 규칙을 따른다면, HTTP 규칙을 따른 어떠한 웹 서버로부터도 웹페이지를 가져올 수 있다.
다른 많은 애플리케이션 계층 프로토콜은 독점이며 공중 도메인에서 찾을 수 없다.
애플리케이션 계층 프로토콜은 네트워크 애플리케이션의 한 요소일 뿐이다.
예를 들어, 웹 애플리케이션은 문서 포맷 표준, 웹 브라우저, 웹 서버, 웹 애플리케이션 계층 프로토콜(HTTP)을 포함하는 여러 요소들로 구성된다.
이 책에서는 중요하고 인기 있는 5개의 애플리케이션 분야에 초점을 맞춘다.
웹은 온디맨드(on-demand) 방식으로 사용자가 원할 때 원하는 것을 수신한다. (라디오, TV와 다른 점)
개인은 또한, 웹 상에서 많은 정보를 얻고 상호작용할 수 있다.
웹 애플리케이션 계층 프로토콜은 웹의 중심이다.
RFC 1945, RFC 7230, RFC 7540에 정의되어 있다.
HTTP는 메시지의 구조 및 클라이언트와 서버가 메시지를 어떻게 교환하는지에 대해 정의하고 있다.
자세히 설명하기 전에 웹 전문 용어들을 알아보자.
웹 페이지들은 객체(object)로 구성된다.
객체는 단순히 단일 URL로 지정할 수 있는 하나의 파일(HTML, JPEG 이미지, 자바스크립트 등)이다.
대부분의 웹 페이지는 기본 HTML 파일과 여러 참조 객체로 구성된다.
예를 들어, 웹 페이지가 HTML 텍스트와 5개의 JPEG 이미지로 구성되어 있으면, 이 웹페이지는 6개의 객체를 갖는다.
기본 HTML 파일은 페이지 내부의 다른 객체를 그 객체의 URL로 참조한다.
URL은 객체를 갖고 있는 서버의 호스트 이름과 객체의 경로 이름을 갖고 있다.
e.g.,
http://www.school.edu/picture.gif
www.school.edupicture.gif웹 브라우저(Web browser)는 HTTP의 클라이언트 측을 구현하기 때문에, 웹의 관점에서 브라우저와 클라이언트(client)라는 용어를 혼용하여 사용한다.
브라우저는 요구한 웹 페이지를 보여주고 여러가지 인터넷 항해와 구성 특성을 제공한다.
웹 서버(Web server)는 URL로 각각을 지정할 수 있는 웹 객체를 갖고 있다.
일반적으로, 사용자가 웹 페이지를 요청할 때
(1) 브라우저는 페이지 내부의 객체에 대한 HTTP 요청 메세지를 서버에게 보내고,
(2) 서버는 요청을 수신하고 객체를 포함하는 HTTP 응답 메시지로 응답한다.
HTTP는
TCP를 전송 프로토콜로 사용한다.
HTTP 요청 메시지를 소켓 인터페이스로 보내고, 소켓 인터페이스로부터 HTTP 응답 메시지를 받는다.이렇게 TCP를 통해 메시지를 보내면 TCP는 신뢰적인 데이터 전송 서비스를 제공하므로
모든 HTTP 요청 메시지가 궁극적으로 서버에 도착한다. (서버에서 보낸 메시지도 마찬가지다.)
HTTP는 TCP가 어떻게 손실 데이터를 복구하고, 올바른 순서로 데이터를 배열하는지 전혀 걱정할 필요가 없어 계층 구조의 장점이 드러난다.
특정 클라이언트가 몇 초 후에 같은 객체를 두 번 요청해도 서버는 전에 보냈다고 알려주지 않고 객체를 또 보낸다.
HTTP 서버는 클라이언트에 대한 정보를 유지하지 않으므로, 비상태(stateless) 프로토콜이라고 부른다.
💡 클라이언트-서버 상호작용이 TCP 상에서 발생할 때 각 요구/응답 쌍이 분리된 TCP 연결을 통해 보내지는 것을 말한다.
웹 페이지를 서버에서 클라이언트로 전송하는 단계를 살펴보자.
페이지가 기본 HTML 파일과 10개의 이미지로 구성되고, 이 11개의 객체가 같은 서버에 있다고 가정하자.
연결 수행 과정은 다음과 같다.
HTTP 기본 포트 80을 통해 서버로 TCP 연결을 시도한다. TCP 연결과 관련하여 클라이언트와 서버에 각각 소켓이 있게 된다.브라우저는 웹 페이지를 수신하면서, 사용자에게 그 페이지를 보여준다. 다른 브라우저는 웹 페이지를 각기 다른 방식으로 해석하여 보여준다.
HTTP는 통신 프로토콜만 정의할 뿐, 웹 페이지에 대한 관심은 없다.
사용자는 앞의 단계를 동시에 받을지 순차적으로 받을지의 동시성 정도를 조절할 수 있도록 브라우저를 구성할 수 있다.
브라우저는 여러 개의 TCP 연결을 설정하며 다중 연결상에서 웹 페이지의 각기 다른 원하는 부분을 요청할 수 있다.
HTTP 1.0은 비지속 연결을 지원한다.
클라이언트가 HTML 파일을 요청하고 그 파일이 클라이언트로 수신될 때까지의 시간을 측정해보자.
이를 위해 RTT를 알아야 하는데,
RTT(round-trip-time)란 작은 패킷이 클라이언트로부터 서버까지 가고, 다시 클라이언트로 되돌아오는 데 걸리는 시간이다.
RTT는 패킷 전파 지연, 큐잉 지연, 처리 지연 등을 포함한다. (1장에 논의되어 있다.)
사용자가 하이퍼링크를 클릭하면, 브라우저와 웹 서버 사이에서 TCP 연결을 시도한다. 이는 3-way handshake를 포함한다.
즉, 클라이언트가 서버로 작은 TCP 메시지를 보내고, 서버는 작은 메시지로 응답하고, 마지막으로 클라이언트가 다시 서버에 응답한다.
서버가 작은 메시지로 응답하면 한 RTT가 계산된다. 이때, 클라이언트는 HTTP 요청 메시지를 TCP 연결로 보내면서 세 번째 응답 부분을 함께 보낸다.
일단, 요청 메시지가 도착하면 서버는 HTML 파일을 TCP 연결로 보내고 이 요청은 또 하나의 RTT를 필요로 한다.
즉, 대략 총 응답 시간은 2RTT와 HTML 파일을 서버가 전송하는 데 걸리는 시간을 더한 것이다.
HTTP/1.1 지속 연결에서 서버는 응답을 보낸 후에 TCP 연결을 그대로 유지한다. (비지속 연결도 지원한다.)
같은 클라이언트와 서버 간의 이후 요청과 응답은 같은 연결을 통해 보내진다.
즉, 같은 서버에 있는 여러 웹 페이지들을 하나의 지속 TCP 연결을 통해 보낼 수 있다.
이들 객체에 대한 요구는 진행 중인 요구에 대한 응답을 기다리지 않고 연속해서 만들 수 있다. (파이프라이닝, pipelining)
일반적으로 HTTP 서버는 일정 기간 사용되지 않으면 연결을 닫는다.
HTTP의 디폴트 모드는 파이프라이닝을 이용한 지속 연결을 사용한다.
RFC는 HTTP 메시지 포맷을 정의한다.

다음은 전형적인 HTTP 요청 메시지이다.
GET /somedir/page.html HTTP/1.1
Host: www.someschool.edu
Connection: close
User-agent: Mozilla/5.0
Accept-language: fr
HTTP 요청 메시지의 첫 줄은 요청 라인이라 부르고, 이후의 줄들은 헤더 라인이라고 부른다.
요청 라인은 3개의 필드, 즉 방식(method) 필드, URL 필드, HTTP 버전 필드를 갖는다.
방식 필드는 GET, POST, HEAD, PUT, DELETE 등의 여러 가지 값을 가질 수 있다.
GET일 때는 비어있고, POST일 때 사용된다.
POST 메시지로 사용자는 서버에 웹 페이지를 요청하고 있으나, 웹 페이지의 특정 내용은 사용자가 폼 필드에 무엇을 입력하는가에 달려 있다.
폼으로 생성한 요구가 반드시 POST일 필요는 없다. 대신에 흔히 요청된 URL의 입력 데이터를 전송한다.
HEAD 방식은 GET과 유사하다.
서버가 HEAD 방식을 가진 요청을 받으면 HTTP 메시지로 응답하는데, 요청 객체는 보내지 않는다. 흔히 디버깅을 위해 사용된다.
PUT 방식은 웹 서버에 업로드할 객체를 필요로 하는 애플리케이션에 의해 사용된다.
DELETE 방식은 사용자 또는 애플리케이션이 웹 서버에 있는 객체를 지우는 것을 허용한다.
다음은 전형적인 HTTP 응답 메시지를 보여준다.
HTTP/1.1 200 OK
Connection: close
Date: Tue, 18 Aug 2015 15:44:04 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 18 Aug 2015 15:11:03 GMT
Content-Length: 6821
Content-Type: text/html
(data data data data data ...)
상태 라인(status line)은 버전 필드와 상태 코드, 해당 상태 메시지를 갖는다.
상태 코드와 메시지
HTTP 명세서는 많은 헤더라인을 정의하고 있고, 위는 그 중 일부다.
브라우저는 브라우저 타입과 여러 설정, 캐싱하고 있는지에 따라 헤더 라인을 동적으로 생성하고 웹 서버도 비슷하다.
HTTP 서버는 상태를 유지하지 않는다.
그러나 서버가 사용자 접속을 제한하거나 사용자에 따라 콘텐츠를 제공하기 원하므로
사용자를 확인하는 것이 바람직할 때가 있는데, 이때 HTTP는 쿠키(cookie)를 사용한다.
over stateless HTTP,
cookieprovides a state related service layer
Set-cookie: 식별 번호의 헤더를 포함해서 전달한다.Cookie : 식별 번호의 헤더를 요청과 함께 보낸다.이렇게 웹 서버는 사용자를 식별할 수 있다.
웹 캐시(cache)(프록시(proxy) 서버)는 기점 웹 서버를 대신하여 HTTP 요구를 충족시키는 개체이다.
Goal: satisfy client request without involving origin server
웹 캐시는 자체의 저장 디스크를 갖고 있어, 최근 호출된 객체의 사본을 저장 및 보존한다.
캐시(cache)는 요청과 응답을 모두 하는 클라이언트이면서 서버이다.
server for original requesting clientclient to origin server일반적으로 웹 캐시는 ISP(university, company, residential ISP)가 구입하고 설치한다.
1 Mb이고, 기관 브라우저로부터 기점 서버에 대한 평균 요청 비율이 초당 15 요청이라고 가정하자.2초라고 가정하자.인터넷 지연이라고 한다.총 응답 시간 = LAN 지연 + 접속 지연 + 인터넷 지연
LAN의 트래픽 강도는 다음과 같다.
(15 요청/초) X (1 Mb/요청) / 100 Mbps = 0.15
접속 회선(라우터와 라우터 사이)의 트래픽 강도는 다음과 같다.
(15 요청/초) X (1 Mb/요청) / 15 Mbps = 1
LAN의 트래픽 강도는 많아야 수십 ms의 지연을 야기하므로 LAN 지연을 무시할 수 있지만,
트래픽 강도가 1에 가까워지면 1.4절에서 논의한 것과 같이 회선의 지연은 매우 커지고 한없이 증가한다.
접속 회선의 접속률을 100 Mbps 수준으로 늘리면 트래픽 강도를 0.15로 낮추어 해결할 수 있겠지만, 매우 많은 비용이 들어간다.
웹 캐시를 사용한 예시를 보자.
캐시가 만족시킨 요청의 비율(hit rate)은 일반적으로 0.2 ~ 0.7이며, 이 예시에서는 0.4의 적중률을 가진다고 가정하자.
일반적으로 0.8 미만의 트래픽 강도는 작은 지연에 속한다. (2초에 의하면 무시할 수 있는 수준이다.)
이들을 고려한 평균 지연은 다음과 같다.
0.4 X 0.01초 + 0.6 X 2.01초 = 1.2....
많은 캐시가 저렴한 PC에서 실행되는 공개 소프트웨어를 사용한다.
콘텐츠 전송 네트워크(CDN)을 통해 웹 캐시는 인터넷에서 점진적으로 중요한 역할을 하고 있다.
CDN 회사는 인터넷 전역을 통해 많은 지역적으로 분산된 캐시를 설치하고 있으며,
이를 통해 많은 트래픽을 지역화하고 있다. (전용 CDN을 사용하기도 한다.)
웹 캐싱이 사용자가 느끼는 응답 시간을 줄일 수 있지만, 웹 캐시 내부에 있는 복사본이 새 것이 아닐 수 있다는 문제를 야기한다.
복사본이 클라이언트에 캐싱된 이후 웹 서버에 있는 객체가 갱신되었을 수도 있기 때문이다.
💡 HTTP는 클라이언트가 브라우저로 전달되는 모든 객체가 최신의 것임을 확인하면서 캐싱해주는데,
이러한 방식을조건부 GET(conditional GET)이라고 한다.
Goal: don't send object if cache has up-to-date cached version
HTTP 요청 메시지가 (1) GET 방식을 사용하고, (2) If-modified-since 헤더를 포함한다면, 그것이 조건부 GET이다.
GET /fruit/kiwi.gif HTTP/1.1
Host: www.exotiquecuisine.com
HTTP/1.1 200 OK
Date: Sat, 3 Oct 2015 15:39:29
Server: Apache/1.3.0 (Unix)
Last-Modified: Wed, 9 Sep 2015 09:23:24
Content-Type: image/gif
(data data data data data ...)
조건부 GET으로 조사를 수행한다.GET /fruit/kiwi.gif HTTP/1.1
Host: www.exotiquecuisine.com
If-modified-since: Wed, 9 Sep 2015 09:23:24
If-modified-since 값이 일주일 전에 서버가 보낸 Last-Modified 값과 완벽히 일치한다.
이 조건부 GET은 서버에게 If-modified-since에 명시된 값 이후 수정된 경우에만 그 객체를 보내라고 한다.
HTTP/1.1 304 Not Modified
Date: Sat, 10 Oct 2015 15:39:29
Server: Apache/1.3.0 (Unix)
(empty entity body)
2020년 현재 주요 웹 사이트 천만 개의 40%가 HTTP/2를 지원하고 있다.
HTTP/2의 주요 목표는 하나의 TCP 연결상에서 멀티플렉싱 요청/응답 지연 시간을 줄이는 데 있으며,
요청 우선순위화, 서버 푸시, HTTP 헤더 필드의 효율적인 압축 기능 등을 제공한다.
HTTP/2는 클라이언트와 서버 간의 데이터 포맷 방법과 전송 방법을 변경했다.
지속적인 연결을 사용할 때 웹 페이지당 오직 하나의 TCP 연결을 가짐으로써,
아래 설명하듯이 서버에서의 소켓 수를 줄이며 전송되는 각 웹 페이지는 공정한 네트워크 대역폭을 가질 수 있다.
그러나 하나의 TCP 상에서 모든 웹페이지를 보내면 HOL(Head of Line) 블로킹 문제가 발생할 수 있다.
비디오 아래 수많은 작은 객체들을 포함할 때 서버와 클라이언트 사이에 저속에서 중간 속도의 병목 링크가 있다고 하자.
비디오 클립은 병목 링크를 통과하는데 오래 걸리는 반면, 작은 객체들은 비디오 클립 뒤에서 기다림이 길어진다.
즉, 비디오 클립이 객체들을 블로킹하게 된다.
HTTP/1.1에서는 여러 개의 병렬 TCP 연결을 열어서 위 문제를 해결해왔다.
TCP 혼잡 제어는 각 TCP 연결이 공정하게 병목 링크를 공유하여 같은 크기의 가용한 대역폭을 공평하게 나누게 해준다.
만일 n개의 TCP 연결이 병목 링크에서 작동하고 있다면, 각 연결은 대략 대역폭의 1/n 씩을 사용하게 된다.
하나의 웹 페이지를 전송하기 위해 여러 개의 병렬 TCP 연결을 열게 함으로써 브라우저는 일종의 속임수로 링크 대역폭의 많은 부분을 받게 된다.
많은 HTTP/1.1 브라우저들은 6개까지 병렬 TCP 연결을 열고 HOL을 막을 뿐만 아니라 더 많은 대역폭을 사용할 수 있게 한다.
HTTP/2의 주요 목표 중 하나는 하나의 웹 페이지를 전송하기 위한 병렬 TCP 연결의 수를 줄이거나 제거하는 데 있다.
이는 서버에서 열고 유지되는 데 필요한 소켓의 수를 줄일 뿐만 아니라 목표한 대로 TCP 혼잡 제어를 제어할 수 있게 하는 데 있다.
그러나 웹 페이지를 전송하기 위해 오직 하나의 TCP 연결만을 사용하게 될 경우에 HTTP/2는 HOL 블로킹을 피하기 위해 신중하게 구현된 메커니즘이 필요하다.
💡
HTTP/2 프레이밍(framing)이란, HTTP 메시지를 독립된 프레임들로 쪼개고, 인터리빙(interleaving)하고, 반대편 사이트에서 재조립하는 것이다.
예를 들어, 비디오 클립과 크기가 작은 객체 8개의 요청이 들어오면, 서버는 9개의 객체를 보내기 위한 TCP 병렬 요청을 받게된다.
이때 (1) 비디오 클립을 1000개의 프레임으로 나누고 (2) 각 객체를 2개의 프레임으로 나누어 비디오 클립으로부터 하나의 프레임을 전송한다.
이후 프레임 인터리빙을 이용하여 각 소형 객체의 첫 번째 프레임을 보내고 이를 반복하여 HOL 블로킹을 피할 수 있다.
HTTP 메시지를 독립된 프레임들로 쪼개고 인터리빙하고 반대편 사이트에서 재조립하는 것이야말로 HTTP/2의 가장 중요한 개선점이다.
프레이밍은 HTTP/2 프로토콜의 프레임으로 구현된 다른 프레이밍 서브 계층에 의해 이루어진다.
서버가 HTTP 응답을 보내고자 할 때, 응답은 프레이밍 서브 계층에 의해 처리되며 프레임들로 나눠진다.
응답의 헤더필드는 하나의 프레임이 되고, 메시지 본문은 하나의 프레임으로 쪼개진다.
응답 프레임들은 서버의 프레이밍 서브 계층에 의해 인터리빙된 후 하나의 지속적인 TCP 연결상에서 전송된다.
프레임들이 클라이언트에 도착하면 프레이밍 서브 계층에서 처음 응답메시지로 재조립되며 브라우저에 의해 처리된다. (클라이언트에서 서버로 요청할 때도 마찬가지이다.)
각 HTTP 메시지를 독립적인 프레임으로 쪼개는 것 외에도 프레이밍 서브 계층은 프레임을 바이너리 인코딩한다.
바이너리 프로토콜은 파싱하기에 효율적이고, 더 작은 프레임 크기를 갖고, 에러에 강하다.
메시지 우선순위화는 개발자들로 하여금 요청들의 상대적 우선 순위를 조정할 수 있게 함으로써 애플리케이션의 성능을 최적화할 수 있게 해준다.
클라이언트가 하나의 특정 서버로 동시에 여러 개의 요청을 할 때, 각 메시지에 1에서 256 사이의 가중치를 부여함으로써 요청에 우선순위를 매길 수 있다.
높은 수치일수록 높은 우선순위를 갖는다.
서버는 가장 높은 우선순위의 요청을 위한 프레임을 제일 먼저 보낼 수 있다.
클라이언트 또한 각 의존도에 따라 메시지의 ID를 지정하여 서로 다른 메시지들 간의 의존성을 나타낼 수 있다.
HTTP/2의 또 다른 특징은 서버로 하여금 특정 클라이언트 요청에 대해 여러 개의 응답을 보낼 수 있게 해주는 데 있다.
처음 요청에 대한 응답 외에도, 서버는 클라이언트의 요청 없이도 추가적인 객체를 클라이언트에게 푸시하여 보낼 수 있다.
이는 HTML 기반 페이지가 웹 페이지를 완벽하게 구동시킬 필요가 있는 객체들을 가리킬 수 있기에 가능하다.
이러한 객체에 대한 HTTP 요청을 기다리는 대신 서버는 HTML을 분석할 수 있고, 필요한 객체들을 식별할 수 있고,
해당 객체들에 대한 요청이 도착하기도 전에 해당 객체들을 클라이언트로 보낸다.
서버는 해당 요청들을 기다리는 데 소요되는 추가 지연을 없앤다.
트랜스 프로토콜인 QUIC(3장에서 다룬다) 위에서 작동하도록 설계된 새로운 HTTP 프로토콜로서, 완전히 표준화된 상태는 아니다.