HTTP/2.0에 대해서 다뤄보려고 한다.
HTTP/2.0의 구성이나 정보들과 HTTP/1.1에서 어떻게 개선이 된건지 왜 이렇게 개선이 됐을까에 대해서 조금 다뤄보려고 한다.
먼저 TPC, HTTP 글을 보고오면 더 좋을듯 하다.
먼저 HTTP는 단순하게 문서 전송을 위해 시작되었지만 시간이 지나며 웹상에서 상호작용하는 빈도수가 높아지고 실시간에 가까운 성능을 요구하는 환경에서는 성능적 한계에 부딪혔다.
Expire&ETag, 다수의 TCP커넥션, 리소스 인라이닝, concatenation srpiting, 도메인샤딩 등 다양한 최적화 방법등이 생겼다.
위 다 적용하기도 힘든 최적화 방법들을 모두 사용하면 충분할까? 근본적인 문제를 해결하면 되지 않을까?
2009년도 중반에 구글에서 발표한 실험적인 프로토콜로서, HTTP 1.1의 잘 알려진 성능적 한계를 해결하여 웹 페이지의 로딩 레이턴시를 줄이는 것이 주된 목표였다.
스피디의 목표중 하나였던 페이지 로딩 시간(PLT)를 50%로 줄인다 라는 목표를 위해 기존의TCP커넥션을 좀 더 효율적으로 활용하는 방법을 택했다. 새로운 바이너리 프레이밍 계층을 도입함으로써 요청과 응답 멀티플렉싱, 우선순위 등을 활성화하고 불필요한 네트워크 레이턴시를 최소화하거나 아예 제거하도록 하였다.
결과는 매우 성공적이였고 HTTP 워킹 그룹(HTTP-WG)이 스피디 프로토콜을 본보기로 삼아 그 장점을 공식 표준화 하고 개발 착수에 들어갔다.
위 내용을 다시보면 1.x표준을 확장하고자 하는것이고 HTTP의 애플리케이션 시맨틱이나 HTTP메서드, 상태코드, URI, HEADER field같은 기존 기능과 핵심 콘셉트에는 바뀌는점은 없다.
그렇다면 뭐가 바뀌었길래 2.0으로 버접을 했을까?
그것은 새 바이너리 프레이밍 계층을 추가한 것이다.
클라이언트와 서버가 데이터를 주고받는 방식이 바뀌어 1.x서버와 클라이언트에는 호환되지 않는다.
HTTP/2.0의 성능 개선의 핵심은 바이너리 프레이밍 계층이다.
바이너리 프레이밍 계층은 소켓 인터페이스와 애플리케이션에게 노출되어 있는 상위 계층 HTTP API 사이를 잇는 새 메커니즘이며 바이너리 인코딩 및 디코딩을 담당한다.
메서드나 헤더 같은 HTTP 시맨틱은 변하지 않았으나 HTTP/2.0을 사용하려면 바이너리 프레이밍 계층이 존재해야 한다.
위 그림에서 보이듯 newline으로 구분되던 Plain Text 인코딩 방식인 HTTP/1.x와 달리 HTTP/2.0에서는 모두 바이너리 형식의 더 작은 메시지와 프레임으로 나뉜다.
바이너리 프레이밍이 도입되 서버와 클라이언트 데이터 교환 방식이 바뀌었다.
스트림
생성된 커넥션 존재하는 가상 채널로 양방향으로 메시지를 전달한다. 각 스트림은 고유의 정수 식별자를 가진다.
메시지
요청,응답 같은 논리적 HTTP메시지이며 하나 이상의 프레임을 포함한다.
프레임
HTTP/2.0 커뮤니케이션에서 사용되는 가장 작은 단위로 각 프레임에는 어느 스트림에 속해있는지 지정하는 프레임 헤더를 포함하고 HTTP Header, 페이로드 같은 데이터를 운반한다.
HTTP/2.0은 양방향 스트림을 운반할 수 있는 커넥션에서 이루어 진다.
각 스트림은 메시지를 이용하여 소통하고 그 메시지는 하나 이상의 프레임으로 이루어져 있다.
HTTP/1.1에서는 한 번에 하나의 응답만을 전달하는 전달 모델때문에 성능 개선을 위해 다수의 TCP연결을 이용했다.
HTTP/2.0 바이너리 프레이밍은 여러개의 HTTP요청과 응답을 독립적인 메시지와 프레임으로 쪼개어 전달한 후 수신 측에서 재구성 하기 때문에 멀티 플렉싱이 가능하다.
위 그림에서 보이듯 클라이언트는 Stream5에 대한 요청을 보내면서도 stream 1,3에 대한 응답도 함께 받고있다.
하나의 TCP커넥션을 사용하면서 다수의 요청을 응답을 병렬도 삽입하더라도 서로 블로킹 되지 않는다.
멀티플렉싱 덕분에 HTTP의 HOL블로킹 문제 또한 해결되었다. (하지만 TCP의 HOL는 해결되지 못했다.)
바이너리 프레이밍에 의한 멀티플렉싱 기능은 더이상 HTTP/1.x처럼 다수의 TCP커넥션을 사용할 필요가 없어젔다.
클라이언트, 서버 모두 오직 하나의 커넥션만 사용하면 된다.
실험 결과에 따르면 클라이언트에서 적은 수의 커넥션을 사용하는 것이 레이턴시에 지속적으로 도움이 된다는 것을 알 수 있었다. HTTP 2.0에서 전송된 전체 패킷 수는 HTTP보다 40% 가량 적었다. 서버가 많은 동시 커넥션을 다루게 되면 확장성의 문제로 발전할 수가 있는데, HTTP 2.0이 이러한 부담을 줄이게 되었다.
-HTTP/2.0Draft 2
단일 커넥션이 TCP사용에 좋은이유
HTTP/2.0에서 HTTP/1.x처럼 다수의 커넥션을 사용하게 된다면 TCP의 처리량을 최대한 활용하지 못할것이고 헤더 압축과 우선순위의 기능 효과가 떨어지게 된다.
HTTP/2.0에서는 메시지의 우선순위를 정하여 애플리케이션의 성능을 최적화 할 수 있다.
각 스트림은 31비트의 우선순위 값을 배정받을 수 있다.
예를들어 DOM을 구성하는데에 CSS와 CSSOM을 구성하기 위해 꼭 필요하다. 그러나 DOM과 CSSOM 모두 자바스크립트 리소스가 없으면 블로킹 되어 구축이 불가능하다.
그리고 이미지와 같은 나머지 리소스들은 낮은 우선순위를 가지게 된다.
클라이언트가 요청을 하나만 보내도 서버는 응답을 여러개 보낼 수 있다.
이제 html, css, js파일 등을 각각 요청하지 않고 한번의 요청으로 모두 받을 수 있다.
만약 서버 푸시 기능을 사용하지 않고 기존의 HTTP/1.x를 사용한다면 리소스 인라이닝 최적화를 진행하거나 css, .js를 각각 요청 응답으로 받아야 할것이다.
HTTP/2.0에서는 헤더 메타데이터를 hpack압축 메커니즘을 사용한다.
위 사진을 보면 두번째 요청에서는 :path만 전송되었다.
2.0은 중복된 헤더 데이터를 전송하지 않으므로 매 요청마다 오버헤드를 대폭 줄일 수 있다.
커넥션이 살아있는 동안 거의 바뀌지않는 user-agent, accept-header등은 단 한번만 전송될것이다.
HTTP/1.x에서는 중복되는 메타 데이터들을 중복으로 보내고 쿠키정보들까지 포함된다면 배보다 배꼽이 더 큰 상황이 많이 발생했다. 이로인한 오버헤드들또한 존재하였지만 HTTP/2에서 해결된 모습을 보인다.