HTTP/2 In action : HTTP/2 프로토콜 기초 - HTTP/2인 이유
- CS/네트워크
- 2024. 5. 12.
들어가기 전
이 글은 HTTP/2 in action 4장을 읽으며 공부한 글입니다.
4.1 HTTP/1.2가 아니라 HTTP/2인 이유
- 바이너리 프로토콜 (프레임 기반으로 메세지를 주고 받음)
- 동기적이 아니라 다중화 (한 커넥션에서 여러 스트림을 보낼 수 있음)
- 흐름 제어 (TCP 수준이 아니라 HTTP/2 수준)
- 스트림 우선순위화
- 헤더 압축 (HTTP/1.1까지는 헤더압축 없음)
- 서버 푸시
HTTP/2는 HTTP/1.x 프로토콜의 성능을 개선하기 위해 만들어진 프로토콜이고, 위 개선점이 존재한다.
일반 개발자들은 개발함에 있어서 HTTP/2, HTTP/1.x를 구분할 필요는 없다. HTTP/2 역시 GET, POST 같은 메서드를 사용해 요청하고 200, 300 같은 응답 코드를 받는 방식으로 동작하기 때문이다.
다만 HTTP/1.x의 성능 개선을 위해 적용된 테크닉들은 HTTP/2에서는 안티 패턴이 되기 때문에 이 부분은 염두해둬야 한다.
4.1.1 텍스트 대신 바이너리
- HTTP/1.1은 텍스트 프로토콜, HTTP/2는 바이너리 프로토콜(프레임을 이용)임.
- 텍스트 프로토콜은 페이로드의 정확한 길이를 알 수 없기 때문에 모든 패킷을 다 받아야 해석해서 서버가 작업할 수 있었음.
- 개선을 위해 HTTP/1.1에서 파이프라이닝, 청크 인코딩이 도입되었음.
- 파이프라이닝, 청크 인코딩 HOL(Head of Line) 블로킹 문제가 존재함. (큐의 가장 앞부분의 거대한 메세지가 안 보내지면, 전송되지 못하고 Block됨)
- HTTP/2는 프레임 단위로 메세지를 보내는 바이너리 프로토콜이며, 이는 TCP의 패킷과 비슷함. 그러나 TCP 위에 HTTP/2가 구현됨.
4.1.2 다중화 된 프로토콜
- HTTP/2는 하나의 커넥션에서 여러 요청을 다중으로 보낼 수 있음. (StreamID 단위로 구분해서 보냄)
- HTTP/2에서 스트림 하나는 HTTP/1.1에서 요청 하나와 매칭됨.
- 각 요청은 Stream ID로 구별됨.
- StreamID 0은 예약된 번호, 홀수는 클라이언트, 짝수는 서버용
- 각 StreamID에 대한 응답은 동일한 StreamID로 응답해야함. (StreamID 1 요청에 대한 응답은 StreamID 1)
- 동일한 Stream ID에서 여러 개의 프레임이 전송될 수 있음.
- 각 프레임은 자신이 속한 StreamId를 가지고 있음.
- HTTP/2는 메세지 전송 수준(바이너리)에서 다르고, 상위 계층에서는 HTTP의 개념이 남아있음. (Method, 응답코드, 헤더 등등)
- HTTP/1은 동기화 된 프로토콜이었다. 요청을 보내면 응답을 받을 때까지 기다려야 했음.
- 현대 웹에서는 한 페이지에 최소 수백 개의 컴포넌트가 존재함.
- HTTP/2는 커넥션 1개만 맺고, 커넥션 내에서 스트림 단위로 요청을 보내 Concurrent하게 컴포넌트를 가져옴.
- HTTP/1.1이 가져오기 위해서는 수백번의 요청을 보내야 함. 커넥션을 수백번 다시 맺어야하므로 많은 시간이 필요함. HTTP/1.1에서는 호스트 당 동시에 여러 커넥션을 맺는 방식으로 로딩 속도를 개선함.
아래 이미지로 살펴보자.
- HTTP/1.1이 첫번째 TCP 커넥션을 맺고 index.html을 가져옴. index.html에는 3개의 Component들이 더 존재함.
- 동시에 TCP 커넥션 3개를 더 맺고, 3개의 Component를 요청함.
- HTTP/2는 첫번째 TCP 커넥션을 맺고 index.html을 가져옴. index.html에는 3개의 Component들이 더 존재함.
- HTTP/2는 기존 TCP 커넥션에서 3개의 요청을 동시에 보냄. (StreamID 별로 나눠서 요청)
- 한 커넥션으로 각 Stream에 대한 응답이 돌아오는데, 이 때 순서는 섞여서 돌아옴.
4.1.3 스트림 우선순위화와 흐름제어
- 우선순위 조절
- HTTP/1.1은 단일 커넥션에서 요청 - 응답흐름이기 때문에 커넥션 레벨에서 우선순위 조절은 필요없었음.
- HTTP/2는 단일 커넥션에서 여러 요청을 보낼 수 있기 때문에 커넥션 레벨에서도 우선순위 조절이 가능하게 함.
- 주로 서버에서 우선순위가 높은 스트림에 대해 더 많은 프레임을 전송하는 형태로 구현됨.
- 흐름 제어
- HTTP/2는 단일 커넥션에서 여러 개의 스트림을 사용함. 클라이언트는 여러 요청(스트림)을 동시에 보내고 동시에 응답 받을 수도 있음.
- 클라이언트가 받은 것을 빠르게 처리할 수 없으면 버퍼링 되어야 하고, 결국에는 처리되지 못해 버려지는 패킷이 생김. 이 경우, TCP 수준에서 재전송이 필요해 짐.
- HTTP/2에서는 위 상황을 방지하기 위해 WINDOW 프레임을 이용해 흐름제어를 지원함.
4.1.4 헤더 압축
- HTTP/1.1
- 헤더 압축이 지원되지 않음.
- 헤더는 예약어로 대부분 반복되는 내용이 많음. (User-Agent, Cookie 등). 따라서 HTTP/1.1 본문 자체의 크기는 굉장히 작은데, 헤더만 거대해지는 경우가 생길 수 있음.
- HTTP/2
- HTTP/2는 헤더 압축을 지원함. (HPACK 같은 것들) 이를 통해 대역폭을 아낄 수 있음.
4.1.5 서버 푸시
- HTTP/1.1에서 요청과 응답은 항상 1:1로 대응해야 했음. (1개의 요청을 보내면 1개의 응답만 와야함.)
- HTTP/2에서는 하나의 요청에 대해 하나 이상의 응답을 내릴 수 있도록 서버 푸시가 구현됨.
- 클라이언트가 index.html을 요청했을 때 서버가 응답하면서, index.html안에 포함된 css, js 파일도 서버 푸시로 함께 내려줄 수 있음.
- 이는 PUSH_PROMISE 프레임을 이용하는 것이고, 특정 요청에 대한 응답(서버 푸시)이기 때문에 요청의 STREAM_ID를 그대로 따름.
- 다만 불필요한 서버 푸시는 대역폭 낭비가 될 수 있음.
- 푸시 된 리소스들이 이미 예전에 캐시된 리소스인 경우, 대역폭 낭비에 해당함.
참고
'CS > 네트워크' 카테고리의 다른 글
Response 객체 쿠키 (0) | 2022.05.29 |
---|---|
멀티미디어 네트워크 (0) | 2022.05.15 |
링크 계층 : 무선 영역 (0) | 2022.05.15 |
HTTP API 설계 예시 (0) | 2021.12.07 |
HTTP 메서드 활용 (0) | 2021.12.06 |