ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [HTTP2 In Action] 4.1. HTTP/2 프로토콜 기초 - 왜 HTTP/1.2 가 아니고 HTTP/2 일까?
    책/HTTP2 In Action 2025. 3. 13. 11:02

     

    드디어 드디어 HTTP/2 기초이다!!

     

    먼저 왜 HTTP/1.2 가 아니라 HTTP/2 일까?

    이런 이유는 하위호환을 깨뜨리는 변화가 있었기 때문이다.

     

    이 하위 호환을 깨뜨리는 변화는 다음과 같다.

     

    • 텍스트 기반 통신이 아닌 바이너리 통신
    • 멀티플렉싱
    • 스트림 우선순위화
    • 헤더 압축
    • 서버 푸시

     

    HTTP/1.0 웹 서버가 HTTP/1.1 웹 서버의 메세지를 이해하고 이후 버전이 추가한 기능을 무시할 수 있지만

     

    HTTP/2 에서는 그렇지 않다.

     

    하지만 그럼에도 같은 TCP 위에서 동작하니 HTTP/1.2 라고 해야하지 않느냐는 이야기가 있는데

     

    그것은 나중에 나온다.

     

    이제 이 변화들에 대해 살펴보자.

     

    바이너리 통신

     

    HTTP/2에서는 기존 청크 방식은 사용하지 않고 바이너리 프로토콜을 적용했다.

     


     

    청크란?

    HTTP 응답 데이터를 여러 개의 "청크(chunk)"로 나누어 순차적으로 전송하는 방법이다.

     

    청크가 가지고 있는 특징은

     

    1. 콘텐츠 길이를 미리 알 필요가 없음:

    전체 응답 크기를 미리 알지 못하는 경우에도 데이터 전송 가능
    Content-Length 헤더를 생략하고 Transfer-Encoding: chunked 헤더 사용


    2. 각 청크의 형식:

    청크 크기(16진수) + CRLF(줄바꿈)
    청크 내용 + CRLF
    마지막에는 크기가 0인 청크로 전송 종료를 표시

     

    2-1. 예시

     

    4\r\n      # 첫 번째 청크의 크기(4바이트)
    Wiki\r\n   # 첫 번째 청크의 내용
    5\r\n      # 두 번째 청크의 크기(5바이트)
    pedia\r\n  # 두 번째 청크의 내용
    0\r\n      # 전송 종료 표시(0 크기 청크)
    \r\n       # 청크 종료 후 빈 줄

     

     

    사용 사례는 실시간 데이터 스트리밍과 서버 센트 이벤트에 사용된다고 한다.

     

    HTTP/1.1 에서 사용할 때는 Transfer-Encoding: chunked 헤더를 명시해야 하지만

     

    HTTP/2 는 이런 전송의 개념을 프로토콜의 자체에 내장했다.

     

    역시 HTTP/1.1 에서는 청크를 쓰더라도 HOL 블로킹은 일어난다.

     


     

    다시 바이너리 프로토콜로 돌아가서

     

    HTTP/2 는 프레임이라는 바이너리 단위로 분할해서 메세지를 보낸다.

     

    이렇게 바이너리로 보내기 때문에 컴퓨터가 파싱하기가 더 쉽다.

     

    멀티플렉싱

    여러 개의 HTTP/1.1 요청은 여러 개의 TCP 연결을 요구했다.

     

    하지만 HTTP/2 는 단일 연결에서 동시에 여러 요청을 보낼 수 있게 되었다.

     

    출처: HTTP/2 in Action

     

    단일 연결에서 동시에 여러 개의 요청을 보낼 수 있는 것은

     

    HTTP/2 프레임이 각각 스트림 식별자를 갖는 바이너리 프레임 계층으로 옮겨갔기에 가능해졌다고 한다.

     

    이런 구조이기 때문에 HTTP/2 연결은 요청을 보낸 다음 응답을 받기까지 블록되지 않는다!

     

    출처: HTTP/2 in Action

     

    그림을 보면 단일 TCP 연결 안에서 여러 스트림이 사용되고 있다.

     

    또 보이는 것은 Stream ID 가 명시되어 있으며 요청에 대한 응답은 동일한 ID 를 사용하는 것과

    클라이언트가 시작한 요청은 홀수 스트림 ID 를 갖는 것이다.

     

    반면에 서버가 시작한 요청은 짝수 스트림 ID 를 사용한다고 한다.

     

    참고로 스트림 아이디 0 은 연결을 관리하고자 클라이언트와 서버 양측이 모두 사용하는 제어 스트림이라고 한다.

     

     

    여기서 나온 두 가지의 핵심 정리는

     

    • HTTP/2 는 여러 개의 바이너리 프레임을 사용해서 단일 TCP 연결을 통해 HTTP 요청 및 응답을 보내는데 다중화된 스트림을 사용한다.
    • HTTP/2 는 주로 메세지 전송 수준에서 다르다. 요청은 메소드(HTTP 메소드) 얻으려는 리소스, 헤더, 본문 ,상태 코드, 캐싱, 쿠키 등 동일한 것을 갖고있다.

     

     

    출처: https://dzone.com/articles/understanding-http2

     

    아 그리고 중요한 점은 스트림은 HTTP/1.1 의 연결과 다르게 재사용되지 않고

     

    완전히 독립적이지 않다는 것이다! 

     

     

    스트림 우선순위

    기존 HTTP/1.1 에서는 단일 요청 및 응답 프로토콜이었으므로 프로토콜 내부에 우선순위화의 필요성이 없었다.

     

    하지만 HTTP/2 는 한 연결에 여러 요청/응답이 있기에 우선순위라는 개념이 필요해졌다.

     

    • 중요 리소스 우선 로딩: 웹페이지에서 HTML, CSS, JavaScript와 같은 중요 리소스에 높은 우선순위를 부여하여 먼저 로드할 수 있다.
    • 사용자 경험 최적화: 사용자에게 먼저 보이는 컨텐츠(뷰포트 내 이미지 등)에 높은 우선순위를 부여할 수 있다.
    • 리소스 간 의존성 관리: JavaScript가 특정 CSS 파일에 의존할 경우, CSS 파일을 먼저 로드하도록 의존성을 설정할 수 있다.

     

    헤더 압축

     

    HTTP 헤더는 클라이언트에서 서버, 또는 그 반대 방향으로 요청 및 응답에 대한 추가적 정보를 보내는데 사용된다.

     

    헤더에는 반복이 많은데 주로 사용되는 헤더를 보자면

     

    • Cookie: 도메인에 대한 모든 요청에 전송된다. 쿠키 헤더는 특히 더 거대해질 수 있고 종종 HTML 문서에 대한 요청 같은 곳에는 필요없지만 모든 요청에 대해 전송된다.
    • User-Agent: 웹서버를 명시하는 헤더이다. 세션 동안 변경되지 않지만 모든 요청에 대해 전송된다.
    • Host: 요청 URL 을 한정하는데 사용되고 동일한 호스트에 대한 요청 각각에 대해 항상 동일하다.
    • Accept: 기대하는 응답의 형식을 정의한다. 브라우저가 지원하는 형식은 일반적으로 브라우저 업그레이드 없이는 변하지 않기 때문에 이 헤더는 요청 형식에 따라 달라지지만, 이러한 형식의 각 인스턴스에 대해서는 동일하다.
    • Accept-Encoding: 이 헤더는 압축 형식을 지원한다. (gzip, deflate, br) Accept 헤더와 비슷하게 세션 내내 동일하다.

     

    이런 헤더는 중복될 수 있으며 낭비이다. 

     

    다운로드 시에 큰 비중을 차지할 수 있다. 

     

    HTTP/1.1 은 본문에 대한 압축만 지원했지만 HTTP/2 는 헤더 압축 개념을 가져왔고 

     

    HTTP 본문 압축 알고리즘의 보안 문제(이후 다룰 예정이다.)로 인해 다른 기법으로 압축한다.

     

     

    서버 푸시

     

    서버에서 브라우저로 응답을 보내는 것이다.

     

    이런 서버 푸시를 동해 첫 응답과 함께 먼저 전송할 수 있다.

     

    하지만, 주의하지 않으면 대역폭 낭비가 일어난다.

     

    브라우저가 필요로 하지 않는 리소스가 푸시된 경우에

     

    이미 브라우저가 해당 리소스를 캐싱하고 있거나 그런 경우 낭비가 일어나고

     

    브라우저가 현재 페이지에서 사용하고 있지 않기에 네트워크 탭에 보이지도 않아

     

    이런 낭비를 확인하기도 어렵기 때문이다.

     

     

     

    요약

    • HTTP/1.2 가 아니고 HTTP/2 인 이유는 HTTP/1.1 과 하위호환을 깨트리는 변화가 생겼기 때문이다.
    • 바이너리 통신, 멀티플렉싱, 스트림 우선순위화, 헤더 압축, 서버 푸시라는 변화이다.
    • HTTP/2 에서는 프레임이 각각 스트림 식별자를 갖는 바이너리 프레임 계층으로 옮겨가서 단일 연결에서 여러 요청과 응답을 받을 수 있게 되었다.
    • 스트림에서는 클라이언트가 시작한 요청은 홀수 스트림 ID 를 갖고 서버가 시작한 요청은 짝수 스트림 ID를 가지며, 0번은 연결을 관리하고자 클라이언트와 서버 양측이 모두 사용하는 제어 스트림이다.
    • 스트림 우선순위는 한 연결에 여러 요청과 응답이 있기에 효율적으로 리소스를 전달하기 위해 만들어졌다.
    • 헤더에는 중복된 헤더들이 많아 낭비가 일어나고 있었으며, HTTP/2 에서는 이러한 헤더도 압축해서 보내고 본문 압축과는 다른 기법으로 압축한다.
    • HTTP/2 는 서버가 브라우저로 응답을 먼저 보낼 수 있는 서버 푸시라는 개념이 있는데 주의해서 사용해야 한다.
Designed by Tistory.