HTTP/2 In action : HTTP/2 프로토콜 기초 - HTTP/2인 이유

    들어가기 전

    이 글은 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에서는 호스트 당 동시에 여러 커넥션을 맺는 방식으로 로딩 속도를 개선함.

    아래 이미지로 살펴보자.

    1. HTTP/1.1이 첫번째 TCP 커넥션을 맺고 index.html을 가져옴. index.html에는 3개의 Component들이 더 존재함.
    2. 동시에 TCP 커넥션 3개를 더 맺고, 3개의 Component를 요청함. 

    1. HTTP/2는 첫번째 TCP 커넥션을 맺고 index.html을 가져옴. index.html에는 3개의 Component들이 더 존재함. 
    2. HTTP/2는 기존 TCP 커넥션에서 3개의 요청을 동시에 보냄. (StreamID 별로 나눠서 요청)
    3. 한 커넥션으로 각 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

    댓글

    Designed by JB FACTORY