HTTP/1.1의 대표적인 문제점
Head of Line(HoL) blocking
- 클라이언트가 서버로 여러 개의 request를 전송할 시, 서버는 요청 받은 순서대로 response를 보내야 한다.
- 서버가 중간 response 작성에 문제가 있는 경우, 이후의 response들은 모두 클라이언트에게 전송되지 못하고 지연(blocking)된다.
![](https://velog.velcdn.com/images/eunna/post/e620da1a-cd75-48a7-81a7-2fa255488f99/image.png)
- HTTP/1.1의 헤더에는 많은 메타 정보들을 저장한다.
- 매 요청 시 중복된 헤더 값을 전송하게 되며(별도의 domain sharding을 하지 않았을 경우), 또한 해당 도메인에 설정된 cookie 정보도 매 요청 시마다 헤더에 포함하여 전송한다.
(참고: domain sharding은 resource 를 여러 개의 domain 으로 나누어 저장하여, page load time 을 향상시키는 일종의 트릭 혹은 방법)
- 전송하려는 값보다 헤더 값이 더 큰 경우도 자주 발생한다.
Limited priorities
- 페이지 내에 존재하는 모든 정보들은 요청에 대한 응답의 우선순위가 존재할 수 있다.
예) 도서 정보 검색 시, 도서 정보의 우선순위가 기타 버튼이나 메뉴의 우선순위보다 높다.
- 그러나 HTTP/1.1에서 페이지 내 모든 정보들은 동일한 우선순위를 가진다. (요청 순서에 따라 응답을 전송하기 때문)
- 사용자가 먼저 요청한 정보를 먼저 제공하기 위해 중요한 정보들에 대한 요청을 먼저 전송하기도 한다.
Client-driven Transmission
- 클라이언트가 서버로 정보를 요청해야만 통신이 가능한 구조이다. 따라서 서버는 클라이언트의 요청이 없으면 정보를 전달할 수 없다.
HTTP/2
Google SPDY (Proprietary Solution)
- 웹 콘텐츠 전송을 위해 구글이 개발한 비표준 네트워크 프로토콜
- 웹 페이지 전송 지연을 줄이고 웹 보안(보안을 기본적으로 제공하며, 선택하여 사용 가능)을 개선하는 목표로, 압축, 다중화, 우선 순위 설정 등을 통해 전송 지연을 감소할 수 있다.
- SSL/TLS로 암호화되지 않은 연결은 지원하지 않는다.
![](https://velog.velcdn.com/images/eunna/post/ff0a3260-25f1-4369-9dbf-a7a68a8d005b/image.png)
HTTP/2 주요 목표
- 줄어든 지연 시간 : HTTP 헤더 필드 압축을 통해 프로토콜의 오버헤드를 최소화한다.
- 응답 다중화 지원 : 요청 별 우선순위 지정을 추가하였다.(하나의 요청이 다른 요청들을 방해하지 않도록 한다 - 독립적)
- 서버 푸시 : 클라이언트에 대해 알고 있는 서버가 클라이언트가 필요하다고 판단되는 것을 미리 제공한다. (지연 시간 개선에 기여)
- 기존 어플리케이션의 수정 없는 지원 : HTTP/1.1로 만들어진 서비스들이 문제 없이, 수정 없이 HTTP/2에서도 돌아갈 수 있도록 한다. - HTTP method, 상태 코드, URI 및 헤더 필드 등을 지원
HTTP/1.2가 아닌 HTTP/2인 이유
![](https://velog.velcdn.com/images/eunna/post/d07260f4-9484-4bd5-aa3d-036984807b16/image.png)
HTTP/1.1의 메시지는 human readable했으나(text 기반 전송), HTTP/2부터는 binary framing 계층을 도입하여 0과 1로 구성된 데이터(binary로 bit level 데이터)를 전송한다.
HTTP/1.1 문제점
- HTTP/1.x에서 성능 개선을 위해 클라이언트가 여러 병렬 요청을 수행하려는 경우, 여러 TCP 연결이 사용된다.
- 이 동작은 HTTP/1.x 전달 모델의 직접적인 결과로 발생하며, 연결당 한번에 하나의 응답만 전달되도록 보장한다.
- 더 안 좋은 점은 HOL(Head-of-Line) 차단과 기본 TCP 연결의 비효율적인 사용을 초래한다는 점이다.
Binary Framing Layer
HTTP/2는 기본적으로 HTTP/1.1에서 사용되는 서비스를 모두 사용할 수 있다.(명령, 헤더, 데이터 모두 동일)
HTTP/2에서는 네트워크 레벨에서 데이터를 주고 받을 때, binary화 되어 데이터가 전송된다.
HTTP/2는 더 작은 메시지와 프레임으로 분할되며, 바이너리 형식으로 인코딩 한다. 클라이언트와 서버는 새 바이너리 인코딩 메커니즘을 사용한다.
HTTP/2 기본 용어
- Stream : 구성된 연결 내에서 전달되는 바이트의 양방향 흐름이 며, 하나 이상의 메시지가 전달될 수 있다(request&response pair 또는 pair들)
- Message : 논리적 요청 또는 응답 메시지에 매핑되는 프레임의 전체 시퀀스이다.(frame 또는 frame들 = message)
- Frame : HTTP/2에서 통신의 최소 단위이며 각 최소 단위에는 하나의 프레임 헤더가 포함된다. 이 프레임 헤더는 최소한으로 프레임이 속하는 스트림을 식별한다.
예시)
![](https://velog.velcdn.com/images/eunna/post/99525465-e35d-4ead-9e97-47abcc4accbe/image.png)
참고) HTTP/2는 여러 개의 데이터를 동시다발적으로 전송할 수 있다.(1개의 TCP 연결 안에서 여러 개의 stream을 통해 데이터들을 주고 받음)
HTTP/2 특징
- 모든 통신은 단일 TCP 연결을 통해 수행되며, 전달될 수 있는 양방향 스트림의 수는 제한이 없다.
- 각 스트림은 양방향 메시지 전달에 사용되는 고유 식별자와 우선순위 정보(선택 사항)가 있다.
- 각 메시지는 하나의 논리적 HTTP 메시지(예: 요청 또는 응답)이며 하나 이상의 프레임으로 구성된다.
- 프레임은 통신의 최소 단위이며 특정 유형의 데이터(예: HTTP 헤더, 메시지 페이로드 등)를 전달한다. 다른 스트림들의 프레임을 인터리빙한 다음, 각 프레임의 헤더에 삽입된 스트림 식별자를 통해 이 프레임을 다시 조립할 수 있다.
요청 및 응답 다중화
HTTP/2 바이너리 프레이밍 계층의 다중화 기능
- HTTP/2는 전체 요청 및 응답 다중화를 지원한다.
- 클라이언트와 서버가 HTTP 메시지를 독립된 프레임으로 세분화하고, 이 프레임을 인터리빙한 다음, 다른 쪽에서 다시 조립한다.
예시) 클라이언트는 DATA 프레임(스트림 5)을 서버로 전송 중인 반면, 서버는 스트림 1과 스트림 3의 인터리빙된 프레임 시퀀스를 클라이언트로 전송한다. 따라서 3개의 병렬 스트림이 존재한다.
![](https://velog.velcdn.com/images/eunna/post/0be6e92b-2204-4cb4-ae4b-8f645215887c/image.png)
HTTP/2 바이너리 프레이밍 계층의 다중화 효과
- 여러 요청을 하나도 차단하지 않고 병렬로 인터리빙 할 수 있다.
- 여러 응답을 하나도 차단하지 않고 병렬로 인터리빙 할 수 있다.
- 단일 TCP 연결을 사용하여 여러 요청과 응답을 병렬 전달 할 수 있다.
- 연결된 파일, 이미지 스프라이트 (image sprites), 도메인 분할과 같은 불필요한 HTTP/1.x 임시 방편을 제거할 수 있다.
- 불필요한 지연 시간을 제거하고 가용 네트워크 용량의 활용도를 개선하여 페이지 로드 시간을 줄일 수 있다.
=> 결론적으로, HTTP/1.x에서 발생하는 문제인 HOL(Head-of Line) 차단을 해결할 수 있으며, 여러 개의 연결이 없어도 요청 및 응답의 병렬 처리와 전달을 지원할 수 있다. 따라서 애플리케이션이 더 빠르고 단순해지고 배포 비용이 절감된다.
스트림 우선 순위 지정
스트림 우선 순위 지원
- HTTP 메시지가 많은 개별 프레임으로 분할될 수 있고 여러 스트림의 프레임을 다중화하는 것이 가능해짐에 따라, 프레임이 클라이언트와 서버에 의해 인터리빙되고 전달되는 순서가 중요한 성능 고려사항이 되었다.
- 이를 위해 HTTP/2 표준에서는 각 스트림이 연관된 가중치와 종속성을 갖도록 허용한다.
- 각 스트림은 1~256 사이의 정수 가중치가 할당될 수 있다.
- 각 스트림은 다른 스트림에 대한 명시적 종속성이 부여될 수 있다.(상하 관계; super-sub)
- 스트림의 종속성 및 가중치 조합을 이용하여 클라이언트가 '우선순위 지정 트리'를 구성하고 통신할 수 있다.
- 이 트리는 클라이언트가 선호하는 응답 수신 방식을 나타낸다.
- 서버는 이 정보를 이용하여 CPU, 메모리 및 기타 리소스의 할당을 제어함으로써 스트림 처리의 우선순위를 지정한다.
- 서버는 우선순위가 높은 응답이 클라이언트에 최적으로 전달되도록 대역폭을 할당한다.
스트림 우선 순위 지원 동작 원리
스트림 종속성
- 자신보다 높은 우선 순위인 또 다른 스트림의 고유 식별자를 상위 요소로 참조하는 방식으로 선언된다.
- 이 식별자가 생략되면 스트림이 '루트 스트림'에 종속된다.(상위 스트림이 없을 때)
- 스트림 종속성 선언은 가능하면 상위 요소 스트림에 종속성보다 리소스가 먼저 할당되어야 함을 나타낸다.
- 예) 응답 C보다 먼저 응답 D를 처리하고 전달해야 한다.
스트림 자원(리소스) 할당
- 동일한 상위 요소를 공유하는 스트림(즉, 동위 요소 스트림)은 그 가중치에 비례하여 리소스가 할당되어야 한다.
- 예) 스트림 A의 가중치가 12이고 그 동위 요소 스트림 B의 가중치가 4인 경우, 이들 스트림이 각각 수신해야 하는 리소스의 비율을 구하려면?
- 모든 가중치를 더함 : 4 + 12 = 16
- 각 스트림 가중치를 총 가중치로 나눔 : A = 12/16, B = 4/16
- 따라서 스트림 A는 가용 리소스의 3/4를 수신하고 스트림 B는 1/4을 수신해야 하며, 스트림 B는 스트림 A에 할당된 리소스의 1/3을 수신해야 한다.
![](https://velog.velcdn.com/images/eunna/post/bcb82c68-506f-4815-a8ec-2d307a662d22/image.png)
스트림 우선 순위 지원 효과
- 다양한 종속성 및 가중치와 여러 가지 리소스 유형이 존재하는 브라우저에서 그 성능을 개선하는데 중요하다.
- HTTP/2 프로토콜은 또한 클라이언트가 기본 설정을 언제든지 업데이트할 수 있도록 허용하므로, 브라우저의 성능이 더욱 최적화된다.
- 즉, 사용자 상호작용과 기타 신호에 응답하여 종속성을 변경하고 가중치를 재할당할 수 있다.
스트림 우선 순위 지원 주의사항
- 스트림의 종속성과 가중치는 전송 기본 설정을 표현하는 것이지 요구사항을 표현하는 것은 아니므로, 특정한 처리나 전송 순서를 보장하지는 않는다.
- 즉, 클라이언트는 스트림 우선순위 지정을 사용하여 특정 순서로 스트림을 처리하도록 서버에게 강요할 수 없다.
One {TCP} connection per origin
HTTP/2의 단일 TCP 연결을 통한 클라이언트-서버 통신
- 모든 HTTP/2 연결은 영구적(웹페이지를 보는 시점부터 클라이언트와 서버가 TCP 세션을 열어서, 다시 접속하더라도 처음의 연결을 유지한다는 것을 의미. 어플리케이션을 실행한 순간부터 끝날 때까지 계속해서 TCP 세션을 유지함)이고 출처당 하나의 연결만 필요하며 이 경우 성능상의 수많은 이점이 있다.
- 연결 수가 적다는 것은 HTTPS 배포의 성능을 개선하는데 특히 중요하다. 연결 수가 적으면 값비싼 TLS 핸드셰이크가 줄어들고, 세션 재사용이 더 향상되며, 필요한 클라이언트 및 서버 리소스가 감소한다.
HTTP/2의 단일 TCP 연결 사용시 성능 개선 사항
- 대부분의 HTTP 전송은 수명이 짧고 폭주(하나의 request에 대해 response로 많은 데이터가 갈 수 있다)하는 반면 TCP는 수명이 긴 대량 데이터 전송에 최적화되어 있다.
- HTTP/2에서는 동일한 연결을 재사용하여 각 TCP 연결을 더 효율적으로 사용할 수 있으며, 또한 전반적인 프로토콜 오버헤드를 대폭 줄일 수 있다.(하나의 연결 내에서 전후 관계를 확인할 수 있기 때문에 이를 활용하여 압축이 가능함)
- 더 적은 연결을 사용하므로 전체 연결 경로(즉, 클라이언트, 중개 장치 및 원본 서버)에서 메모리와 처리량이 줄어든다.
- 그 결과 전체 운영 비용이 절감되고 네트워크 활용도와 용량이 개선된다.
- 따라서 HTTP/2로 전환하면 네트워크 지연 시간이 줄어들 뿐만 아니라 처리량이 개선되고 운영 비용이 줄어든다
흐름 제어
일반적인 흐름 제어
- 수신단에서 송신단의 데이터가 불필요하거나 처리가 불가능한 경우, 수신단에 부담을 주는 것을 막을 수 있다.
- 예시)
- 수신단이 사용 중이거나, 과부하 상태이거나, 특정 스트림에 일정 크기의 리소스만 할당하려는 다음과 같은 경우들
- 클라이언트가 높은 우선순위로 대용량 동영상 스트림을 요청했지만 사용자가 이 동영상을 일시 중지하여 이제 클라이언트가 불필요한 데이터 가져오기와 버퍼링을 막기 위해 서버로부터의 동영상 전달을 일시 중지하거나 차단하려고 하는 경우
- 프록시 서버의 다운스트림 연결은 빠르고 업스트림 연결은 느린 경우, 프록시 서버가 업스트림 속도에 맞게 다운스트림의 데이터 전달 속도를 조절하여 리소스 사용량을 제어하는 경우 등
HTTP/2 흐름 제어 특징
- 흐름 제어를 구현하기 위한 특정 알고리즘을 지정하지 않는다.
- 그 대신 간단한 빌딩 블록을 제공하고 그 구현을 클라이언트와 서버에 넘긴다.
- 그러면 클라이언트와 서버가 이 빌딩 블록을 사용하여 사용자 설정 전략을 구현하여 리소스 사용과 할당을 제어한다.
- 웹 어플리케이션의 실제 성능과 측정된 성능을 모두 개선할 수 있는 새로운 전달 기능도 구현하도록 지원한다.
- 예를 들어, 애플리케이션 계층 흐름 제어에서는 브라우저가 특정 리소스의 일부분만을 가져온 후, 스트림 흐름 제어 창을 0으로 줄여서 가져오기를 보류한 다음, 나중에 가져오기를 재개할 수 있도록 허용한다.
- 즉, 브라우저가 특정 이미지의 미리보기나 최초 스캔을 가져와서 표시할 수 있고, 우선순위가 더 높은 다른 가져오기 동작을 진행할 수 있으며, 더 많은 주요 리소스가 로딩된 후에 가져오기를 재개할 수 있다.
HTTP/2 흐름 제어 동작 원리
서버 푸시
서버 푸시 기능
- HTTP/1.1에서 불가능한 기능으로, 서버는 원래 요청에 응답할 뿐만 아니라 클라이언트가 명시적으로 요청하지 않아도 서버가 추가적인 리소스를 클라이언트에 푸시할 수 있다.
![](https://velog.velcdn.com/images/eunna/post/1874bc09-bbe4-443b-9150-603c6b755b6e/image.png)
서버 푸기 기능의 필요성
- 서버 입장에서 다음에 사용될 리소스를 미리 푸시하면 사용자 입장에서의 지연 속도(사용자 체감 속도)가 줄어들 것이다.
- 하나의 파일에 CSS, JavaScript를 함께 넣어서 보내는 것도 서버 푸시의 일종으로 볼 수 있다.
HTTP/2 서버 푸시 동작
-
서버가 미리 PUSH_PROMISE 프레임들을 클라이언트에게 보낼 것이라고 알려준다. (헤더 정보를 미리 보냄)
; 클라이언트가 push promise를 받지 않을 수도 있기 때문에 미리 알려주는 것이 중요함.
-
클라이언트는 해당 정보가 이미 캐시 정보에 있다는 등의 이유로 RST_STREAM frame을 전송하여 PUSH_FRAME을 거절할 수 있다.
-
클라이언트가 PUSH_FRAME을 받으려고 하면, 클라이언트는 서버가 보내려고 하는 pushed stream의 개수를 제한할 수 있다. 또한 flow control window도 제어할 수 있다. 이러한 과정은 SETTINGS frame을 통해서 이루어진다.
; 다양한 제어 방법이 존재
-
클라이언트가 정한 조건에 따라 서버는 리소스를 푸시를 할 수 있다. 각각의 리소스는 multiplex되고, 우선순위가 존재하며, 클라이언트에 의해 처리된다.
; stream들이 한 개의 TCP 연결 내에 있고 보안 관련 암호화 작업은 TCP level에서 이루어지기 때문에 각 stream들은 추가적인 암호화를 할 필요가 없다 = same-origin policy
헤더 압축
- HTTP/1.x : 500~800 바이트의 HTTP 헤더가 매 전송마다 추가적으로 전송되며, HTTP cookie들이 사용되면 몇 킬로바이트까지 추가된다.
- HTTP/2 : HPACK 압축을 통해서 request와 response 헤더를 압축한다.
HTTP/2의 HPACK 압축 포맷
- 허프만 코드(Huffman code; 원본 대비(이전 데이터) 차이값을 전송하는 방식)를 사용해서 전송 크기를 줄인다.
- 하나의 스트림 안에 있는 HTTP request/response들은 독립적이지 않기 때문에 이전 헤더에서 바뀌는 것이 없다면 다시 보내지 않는다.
Huffman coding
앞서 보낸 정보와 달라진 정보만 다음 메시지 에서 보내는 “과거와 현재의 차이 기반 압축” 기술이다
예시
Request #2는 달라진 path 정보만 전송한다.
![](https://velog.velcdn.com/images/eunna/post/e8a1ad1d-7837-4598-b251-a6b3d67cafcb/image.png)
HTTP/1.1 헤더 vs HTTP/2 헤더
- HTTP/1.1 : 두 개의 요청 헤더에 중복 값을 그냥 중복 전송한다.
- HTTP/2 : 헤더에 중복값이 존재하는 경우 Header Table 개념을 사용하여 중복 헤더를 검출하고 중복된 헤더는 index값만 전송한다. 중복되지 않은 Header 정보의 값은 Huffman 인코딩하여 전송한다.
- Static table : 명세에 의해 정의되며, 대부분의 연결에서 자주 사용되는 HTTP 헤더 필드들을 제공하는 테이블
- Dynamic table : 초기에는 비어 있다가 특정 연결 내에서 바뀌는 값에 대해서 업데이트되는 테이블
- 따라서 1) static table의 값과 다른 경우에는 Huffman coding을 통해 기존 값과 달라진 값을 전송하고, 2) static table과 dynamic table에 이미 있는 값들은 인덱스만 전송한다.
![](https://velog.velcdn.com/images/eunna/post/689b7be6-71c1-4857-b486-5d67d44627d3/image.png)