카테고리 없음

[HTTP 이해하기 3편] HTTP/2는 무엇이고, HTTP/1.1과 무엇이 달라졌을까

지기(ZIGI) 2026. 2. 22. 16:23

today keys : HTTP/2, 바이너리 프레이밍, 스트림, 프레임, 멀티플렉싱, HPACK, 헤더 압축, TCP, HOL Blocking


지난 글에서 HTTP/1.1을 웹 통신의 기본 기준점으로 살펴봤다면, 이번에는 그다음 단계인 HTTP/2를 볼 차례입니다.

HTTP/2는 HTTP를 완전히 새로 만든 프로토콜이 아니라, 기존 HTTP 의미를 더 효율적으로 전달하기 위해 다듬은 버전입니다.

RFC 9113은 HTTP/2를 "HTTP semantics의 optimized expression"이라고 설명하고, 같은 연결에서 여러 교환을 동시에 처리하고 헤더 필드를 더 효율적으로 다루도록 설계되었다고 정의합니다.

이번 포스팅에서는 HTTP/2의 핵심 구조를 중심으로, HTTP/1.1과 무엇이 달라졌는지를 정리해봅니다.



HTTP/2 등장 배경

시간이 지나면서 웹 페이지는 단순한 문서가 아니라 수많은 이미지, CSS, JavaScript, API 호출이 얽힌 복합적인 애플리케이션 형태로 바뀌었습니다.

하나의 페이지를 띄우는 데 필요한 요청 수가 크게 늘었고, HTTP/1.1의 연결 구조와 반복적인 헤더 전송 방식은 점점 더 큰 부담이 되었습니다.

MDN도 이런 변화 때문에 HTTP/1.1 연결의 복잡성과 오버헤드가 커졌고, 그 문제를 해결하기 위한 흐름이 HTTP/2로 이어졌다고 설명합니다.

바이너리 프레이밍

HTTP/1.1과 비교했을 때 가장 눈에 띄는 차이는 텍스트 기반에서 바이너리 기반으로 바뀌었다는 점입니다.

HTTP/1.1 메시지는 사람이 그대로 읽을 수 있는 텍스트 형식이었지만, HTTP/2는 메시지를 프레임이라는 바이너리 구조로 잘라서 전송합니다.

MDN은 HTTP/2를 binary protocol이라고 설명하고, RFC 9113도 binary message framing을 통해 더 효율적인 메시지 처리를 가능하게 한다고 설명합니다.

RFC 9113에 따르면 모든 프레임은 고정된 9바이트 헤더로 시작하고, 그 뒤에 가변 길이의 payload가 붙습니다.

헤더 안에는 길이, 타입, 플래그, 스트림 식별자 같은 정보가 들어가고, 실제 의미는 프레임 타입에 따라 달라집니다.

HTTP/2에서 "하나의 요청"이나 "하나의 응답"은 더 이상 텍스트 한 덩어리로 흘러가는 것이 아니라, 여러 프레임으로 잘려서 연결 위를 이동합니다.

 

스트림과 멀티플렉싱

바이너리 프레이밍과 함께 등장하는 개념이 스트림(stream)입니다.

스트림은 하나의 HTTP 요청과 응답이 지나가는 논리적인 통로라고 생각하면 이해하기 쉽습니다.

RFC 9113은 스트림이 31비트 정수 식별자로 구분되며, 연결 전체를 위한 제어 메시지는 stream id 0을 사용한다고 설명합니다.

하나의 TCP 연결 안에 여러 개의 스트림이 동시에 존재할 수 있고, 각 스트림이 서로 다른 요청과 응답을 담당하게 됩니다.

이 구조 덕분에 HTTP/2의 대표적인 특징인 멀티플렉싱(multiplexing)이 가능해집니다.

HTTP/1.1에서는 병렬 요청을 늘리려면 TCP 연결을 여러 개 열어야 했지만, HTTP/2에서는 하나의 TCP 연결 안에서 여러 스트림의 프레임을 섞어서 보낼 수 있습니다.

브라우저가 CSS, JavaScript, 이미지, 폰트를 추가로 요청한다고 해보면, HTTP/1.1에서는 여러 TCP 연결을 병렬로 열어야 했지만 HTTP/2에서는 하나의 연결 안에 여러 스트림을 만들어 동시에 진행할 수 있습니다.

RFC 9113은 이 방식이 HTTP/1.x보다 더 적은 TCP 연결을 사용하게 해주고, 네트워크 활용 효율이 높아질 수 있다고 설명합니다.

헤더 압축, HPACK

HTTP/2의 또 다른 중요한 변화는 헤더 압축입니다.

쿠키, User-Agent, Accept 계열 헤더처럼 비슷한 값이 여러 요청에서 반복되는 경우가 많습니다.

MDN은 HTTP/1.x에서 본문 압축은 가능해도 헤더 압축은 사실상 하지 못했고, HTTP/2는 이 중복을 줄이기 위해 헤더를 압축한다고 설명합니다.

RFC 9113은 각 연결마다 HPACK 인코더/디코더 상태를 유지하면서 field block을 압축하고 복원한다고 설명합니다.

현대 웹에서는 아주 많은 요청이 짧은 시간 안에 오가는데, 그때마다 비슷한 헤더를 반복해서 보내는 비용이 무시하기 어렵습니다.

HTTP/2의 장점이 단지 "속도가 더 빠르다"가 아니라, 이런 구조적 중복을 줄이는 데 있다는 점을 함께 봐야 합니다.

 

pseudo-header

HTTP/2 메시지를 볼 때는 pseudo-header 개념도 알아둘 필요가 있습니다.

HTTP/1.1에서는 첫 줄에 start-line이 있었지만, HTTP/2에서는 이 정보를 :method, :scheme, :authority, :path 같은 특별한 헤더 필드로 표현합니다.

응답에서는 :status가 상태 코드를 담습니다.

HTTP/1.1에서 아래처럼 보이던 요청이,

GET /index.html HTTP/1.1
Host: example.com
Accept: text/html

 

HTTP/2에서는 내부적으로 아래와 비슷한 의미로 표현됩니다.

:method: GET
:scheme: https
:authority: example.com
:path: /index.html
accept: text/html

 


형식은 달라졌지만, "어떤 경로를 어떤 방식으로 요청하는가"라는 의미는 그대로 유지됩니다.

HTTP/2를 볼 때는 의미는 유지되고 표현 방식이 바뀌었다는 점을 기준으로 삼는 것이 좋습니다.

 

HTTP/2의 장단점

가장 큰 장점은 하나의 연결을 더 효율적으로 사용할 수 있다는 점입니다.

멀티플렉싱으로 여러 요청과 응답을 동시에 처리할 수 있고, 헤더 압축으로 중복 데이터를 줄일 수 있으며, 연결 수를 줄여 네트워크 자원을 더 효율적으로 활용할 수 있습니다.

리소스가 많은 현대 웹 페이지나 짧은 시간 안에 여러 요청이 오가는 환경에서 특히 유리합니다.

반면 한계도 분명합니다.

HTTP/2는 애플리케이션 수준의 head-of-line blocking을 줄였지만, TCP 자체의 head-of-line blocking까지 해결한 것은 아닙니다.

RFC 9113은 이 프로토콜이 TCP head-of-line blocking을 해결하지 않는다고 명시하고 있고, 하나의 패킷 손실이 발생하면 그 연결 위의 다른 스트림들도 영향을 받을 수 있습니다.

또한 HTTP/1.1은 텍스트라서 요청/응답 흐름을 눈으로 읽기 쉬웠지만, HTTP/2는 프레임과 스트림 구조를 이해해야 하고 바이너리 표현을 도구로 해석해야 합니다.

운영이나 트러블슈팅 관점에서는 "더 효율적인 대신 내부 구조를 조금 더 알아야 하는 프로토콜"이라고 보는 편이 현실적입니다.

정리하면 HTTP/2는 HTTP/1.1의 의미를 유지하면서도, 그 전달 방식을 훨씬 더 효율적으로 바꾼 프로토콜입니다.

텍스트 기반 메시지를 바이너리 프레임으로 나누고, 하나의 TCP 연결 안에 여러 스트림을 만들어 멀티플렉싱을 가능하게 했으며, HPACK 기반 헤더 압축으로 반복적인 오버헤드를 줄였습니다.

다만 TCP 위에서 동작하는 이상 전송 계층의 HOL 문제까지 사라지는 것은 아니며, 구조가 복잡해진 만큼 내부 동작을 이해하는 데는 조금 더 공부가 필요합니다.

다음 포스팅에서는 HTTP/1.1과 HTTP/2를 실무 관점에서 나란히 비교해보겠습니다.