HTTP/2
1. 개요
1. 개요
HTTP/2는 월드 와이드 웹에서 사용되는 핵심 프로토콜인 HTTP의 두 번째 주요 개정판이다. 2015년 IETF의 HTTP 워킹 그룹에 의해 RFC 7540으로 표준화되었으며, 기존 HTTP/1.1의 문법과 의미론을 유지하면서 네트워크 리소스 사용 효율과 지연 시간을 개선하는 데 주안점을 두었다.
이 프로토콜은 웹 페이지 로딩 속도를 높이고 네트워크 대역폭 사용을 최적화하기 위해 설계되었다. HTTP/1.1이 텍스트 기반 프로토콜이었다면, HTTP/2는 효율성을 위해 바이너리 프레이밍 계층을 도입했다. 이는 기존의 HTTP 메서드, 상태 코드, 헤더 필드와 같은 개념을 그대로 유지하면서도 데이터를 전송하는 방식을 근본적으로 바꾼 것이다.
HTTP/2의 주요 목표는 단일 연결을 통해 여러 요청과 응답을 동시에 다중화하여 레이턴시를 줄이는 것이다. 또한 헤더 압축 기술인 HPACK을 도입하여 반복되는 헤더 데이터의 오버헤드를 크게 줄였고, 서버 푸시 기능을 통해 클라이언트의 요청을 예측하여 필요한 리소스를 사전에 전송할 수 있게 했다. 이러한 변화들은 현대의 복잡한 웹 애플리케이션이 직면한 성능 병목 현상을 해결하기 위한 것이다.
2. HTTP/2의 등장 배경과 목표
2. HTTP/2의 등장 배경과 목표
HTTP/1.1은 1999년 표준화된 이후 10년 이상 인터넷의 핵심 프로토콜로 자리 잡았다. 그러나 웹 페이지가 점점 복잡해지고 리소스 수가 급증하면서 프로토콜의 설계적 한계가 성능 병목 현상으로 드러나기 시작했다. 이러한 한계를 극복하고 웹의 전반적인 성능을 개선하기 위해 HTTP/2가 등장하게 되었다.
주요 성능 개선 목표는 대기 시간을 줄이고 네트워크 자원의 활용도를 높이는 것이었다. 구체적으로는 단일 연결 내에서 여러 요청과 응답을 동시에 처리할 수 있는 다중화 지원, 불필요하게 중복 전송되는 헤더 데이터의 압축, 그리고 서버가 클라이언트의 명시적 요청 없이도 리소스를 사전에 전송할 수 있는 서버 푸시 기능 도입 등이 핵심 목표에 포함되었다. 이는 기존 HTTP/1.1의 근본적인 동작 방식을 개선하려는 시도였다.
한계 요소 (HTTP/1.1) | 설명 | HTTP/2의 해결 방향 |
|---|---|---|
연결 당 하나의 요청-응답만 순차 처리하여 지연 발생 | ||
헤더 중복 | 동일 도메인 요청 시 매번 비슷한 헤더를 평문으로 전송 | |
연결 수 과다 | 병렬 처리를 위해 여러 TCP 연결을 생성하여 오버헤드 발생 | 단일 지속 연결로 모든 통신 처리 |
서버 주도성 부재 | 클라이언트 요청에만 응답할 수 있어 최적화 제한 | 서버 푸시를 통한 사전 리소스 전송 가능 |
이러한 배경 하에, 구글의 SPDY 프로토콜을 기반으로 한 HTTP/2 사양이 IETF에 의해 2015년 공식 표준(RFC 7540)으로 발표되었다. HTTP/2는 기존의 HTTP 시맨틱스(요청 메서드, 상태 코드, 헤더 필드 등)는 그대로 유지하면서 전송 효율성만을 혁신적으로 개선하는 데 주력했다. 이는 기존 웹 애플리케이션이 수정 없이도 프로토콜의 혜택을 받을 수 있도록 하기 위한 중요한 설계 원칙이었다[1].
2.1. HTTP/1.1의 한계
2.1. HTTP/1.1의 한계
HTTP/1.1은 1999년 표준화된 이후 웹의 근간을 이루어왔으나, 현대 웹 애플리케이션의 복잡성과 높은 성능 요구사항 앞에서 여러 구조적 한계를 드러냈다.
가장 큰 문제는 HOL 블로킹이다. HTTP/1.1은 기본적으로 하나의 TCP 연결 당 한 번에 하나의 요청과 응답만을 처리할 수 있다. 여러 자원을 병렬로 받기 위해 브라우저는 동일한 도메인에 대해 여러 개의 TCP 연결을 동시에 생성하는 방법을 사용했으나, 이는 연결 수에 제한이 있고 각 연결의 설정 및 유지에 따른 오버헤드가 크다. 또한, 하나의 연결에서 앞선 요청의 응답이 지연되면 뒤따르는 모든 요청이 대기해야 하는 현상이 발생하여 전체 페이지 로딩 시간이 길어졌다.
두 번째 한계는 비효율적인 헤더 전송 방식이다. HTTP/1.1은 텍스트 기반의 프로토콜로, 매 요청마다 반복되고 장황한 헤더 정보를 평문으로 전송한다. 특히 쿠키 정보가 포함되면 헤더의 크기가 크게 증가하며, 이는 매 요청마다 중복되어 네트워크 대역폭을 낭비하고 지연을 유발하는 주요 원인이 되었다.
세 번째로, 클라이언트 주도적인 통신 모델이 문제가 되었다. 서버는 클라이언트가 요청한 리소스만을 보낼 수 있으며, 클라이언트가 해당 리소스의 존재를 미리 알지 못하면 요청 자체를 할 수 없다. 이는 예를 들어, 서버가 HTML 문서를 분석한 후 해당 문서 렌더링에 필요한 CSS나 자바스크립트 파일을 클라이언트의 추가 요청 없이 미리 보낼 수 없음을 의미한다. 이로 인해 불필요한 왕복 지연이 발생한다.
한계점 | 설명 | 결과 |
|---|---|---|
HOL 블로킹 | 단일 연결 내에서 요청/응답이 순차적으로 처리됨 | 리소스 병렬 전송 비효율, 지연 증가 |
비효율적 헤더 | 중복된 텍스트 헤더의 반복 전송 | 대역폭 낭비, 지연 증가 |
클라이언트 주도 모델 | 서버가 클라이언트 요청 없이 리소스를 능동적으로 보낼 수 없음 | 불필요한 왕복 지연 발생 |
이러한 한계들은 웹 페이지가 점점 더 많은 수의 리소스(이미지, 스크립트, 스타일시트 등)로 구성되면서 성능 병목 현상을 심화시켰고, 이를 해결하기 위한 다양한 우회 기술(도메인 샤딩, 이미지 스프라이트, 코드 압축 등)이 등장했으나 근본적인 해결책이 되지 못했다. 이러한 배경에서 HTTP/2는 프로토콜 자체의 구조적 개선을 통해 성능 문제를 근본적으로 해결하고자 설계되었다.
2.2. 성능 개선 목표
2.2. 성능 개선 목표
HTTP/2의 주요 설계 목표는 HTTP/1.1의 한계를 극복하여 웹 페이지 로딩 속도를 개선하고 네트워크 자원 사용 효율을 높이는 것이었다. 구체적인 성능 개선 목표는 다음과 같다.
첫 번째 목표는 지연 시간을 줄이는 것이었다. HTTP/1.1에서는 하나의 TCP 연결 당 한 번에 하나의 요청-응답만 처리할 수 있어, 여러 자원을 받기 위해선 순차적 요청이나 다수의 병렬 연결이 필요했다. 이로 인한 헤드 오브 라인 블로킹 문제가 지연을 유발했다. HTTP/2는 단일 연결 내에서 여러 요청과 응답을 동시에 처리할 수 있도록 하여 이 문제를 해결하고자 했다.
두 번째 목표는 프로토콜 오버헤드를 최소화하는 것이었다. 텍스트 기반의 HTTP/1.1과 달리 바이너리 프레이밍 계층을 도입하여 메시지를 파싱하고 전송하는 효율을 높였다. 또한, HPACK 알고리즘을 통한 헤더 압축을 의무화하여 반복되고 장황한 HTTP 헤더로 인한 오버헤드를 상당히 줄였다.
마지막으로, 서버가 클라이언트의 요청을 미리 예측하여 자원을 능동적으로 제공할 수 있는 서버 푸시 기능을 도입했다. 이는 클라이언트가 추가 요청을 보내기 전에 필요한 자원(예: CSS 파일, 자바스크립트 파일)을 먼저 전송함으로써 왕복 횟수를 줄이고 전체 로딩 시간을 단축하는 데 기여했다.
3. 핵심 기능과 특징
3. 핵심 기능과 특징
HTTP/2의 핵심 기능은 HTTP/1.1의 성능 한계를 해결하기 위해 설계된 여러 새로운 메커니즘으로 구성된다. 가장 근본적인 변화는 텍스트 기반 프로토콜에서 바이너리 프레이밍 계층으로의 전환이다. 이 계층은 통신을 더 작고 관리하기 쉬운 단위인 프레임으로 분할하여 처리한다. 이 변경으로 인해 데이터 파싱이 더 효율적이고 빠르며, 프레임 오류 발생 가능성이 줄어든다.
이 바이너리 프레이밍 위에 구축된 주요 개념은 스트림, 메시지, 프레임의 계층적 구조이다. 하나의 TCP 연결 내에서 여러 개의 독립적인 양방향 스트림이 동시에 존재할 수 있다. 각 스트림은 하나의 요청과 그에 대한 응답인 메시지를 전달하며, 이 메시지는 다시 헤더 프레임과 데이터 프레임과 같은 여러 프레임으로 나뉘어 전송된다. 이를 통해 단일 연결에서 여러 요청과 응답을 다중화할 수 있어, HTTP/1.1의 HOL 블로킹 문제를 해결하고 연결 효율성을 극대화한다.
헤더 전송 효율을 높이기 위해 HTTP/2는 HPACK이라는 헤더 압축 방식을 도입했다. 이는 허프만 코딩과 함께 이전에 전송된 헤더 필드 값을 참조하는 정적 및 동적 테이블을 사용한다. 반복되는 헤더(예: User-Agent, Cookie)는 매우 작은 크기로 압축되어 대역폭을 절약한다. 또한 중요한 기능 중 하나인 서버 푸시는 클라이언트가 특정 리소스를 요청했을 때, 서버가 해당 리소스와 연관된 추가 리소스(예: HTML 문서에 필요한 CSS 파일)를 클라이언트의 명시적 요청 없이도 미리 보낼 수 있게 한다. 이를 통해 왕복 시간을 줄일 수 있다.
기능 | 설명 | 목적 |
|---|---|---|
바이너리 프레이밍 | 통신을 프레임 단위로 구조화 | 파싱 효율성 향상, 오류 감소 |
다중화 | 단일 연결 내 여러 스트림 동시 처리 | HOL 블로킹 제거, 연결 효율화 |
HPACK 헤더 압축 | 정적/동적 테이블을 이용한 헤더 압축 | 대역폭 절약 |
서버 푸시 | 클라이언트 요청 전에 관련 리소스 전송 | 왕복 시간 감소 |
이러한 기능들은 상호 연계되어 작동한다. 예를 들어, 다중화된 스트림은 각각 우선순위를 가질 수 있으며, 흐름 제어를 통해 리소스 소비를 관리한다. 결국 HTTP/2는 기존의 HTTP 의미 구조(메서드, 상태 코드, 헤더)는 그대로 유지하면서, 데이터 전송 방식을 근본적으로 재설계하여 웹 페이지 로딩 성능을 획기적으로 개선했다.
3.1. 바이너리 프레이밍 계층
3.1. 바이너리 프레이밍 계층
HTTP/2의 핵심 변화는 텍스트 기반의 HTTP/1.1 프로토콜을 바이너리(이진) 프로토콜로 전환한 데 있다. HTTP/1.1은 사람이 읽을 수 있는 텍스트 형식으로 메시지를 구성했지만, HTTP/2는 효율적인 기계 처리를 위해 설계된 바이너리 프레이밍 계층을 도입했다. 이 계층은 모든 통신을 더 작고 관리하기 쉬운 단위인 프레임으로 나누어 캡슐화한다.
바이너리 프레이밍은 프로토콜의 효율성과 강건성을 크게 향상시킨다. 텍스트 파싱은 모호성과 오류가 발생하기 쉬운 반면, 바이너리 형식의 프레임은 구문 분석이 빠르고 명확하다. 또한 프레임은 HTTP/2 연결 내에서 여러 요청과 응답이 뒤섞이는 다중화를 가능하게 하는 기본 단위가 된다. 각 프레임에는 해당 프레임이 속한 논리적 스트림을 식별하는 스트림 식별자가 포함되어 있어, 단일 TCP 연결을 통해 여러 스트림의 프레임이 인터리빙되어 전송될 수 있다.
다음은 HTTP/2에서 정의된 주요 프레임 유형의 예시이다.
프레임 유형 | 용도 |
|---|---|
| HTTP 헤더를 전송한다. |
| 메시지 본문(payload)을 전송한다. |
| 스트림의 우선순위를 지정한다. |
| 스트림을 비정상적으로 종료한다. |
| 연결 매개변수를 협상한다. |
| 서버가 푸시할 리소스를 알린다. |
| 연결 지연 시간을 측정하거나 유지(keep-alive)를 확인한다. |
| 연결 종료를 시작하거나 오류를 알린다. |
이러한 구조적 변화로 인해 HTTP/2는 HTTP/1.1의 줄바꿈으로 구분된 텍스트 명령을 처리할 때 발생하던 성능 오버헤드와 보안 문제(예: 요청 스머글링)를 제거했다. 최종적으로 애플리케이션 계층에 보여지는 HTTP 세맨틱스(요청, 응답, 헤더, 본문 등)는 변경되지 않지만, 그 아래에서 데이터가 전송되는 방식은 근본적으로 달라졌다.
3.2. 스트림, 메시지, 프레임
3.2. 스트림, 메시지, 프레임
HTTP/2는 HTTP/1.1의 텍스트 기반 프로토콜에서 벗어나, 효율적인 전송을 위해 바이너리 프레이밍 계층을 도입했다. 이 계층은 통신의 기본 단위를 재정의하며, 스트림, 메시지, 프레임이라는 세 가지 핵심 개념으로 구성된다.
가장 작은 단위는 프레임이다. 프레임은 바이너리 형식으로 인코딩되며, 특정 유형의 정보를 담는다. 주요 프레임 유형은 다음과 같다.
프레임 유형 | 용도 |
|---|---|
HTTP 요청 또는 응답 헤더를 전송한다. | |
요청 또는 응답의 본문(payload)을 전송한다. | |
스트림의 우선순위를 설정한다. | |
스트림을 비정상적으로 종료한다. | |
연결 매개변수를 협상한다. | |
서버가 클라이언트에게 푸시할 리소스를 알린다. |
이러한 프레임들이 모여 하나의 완전한 요청 또는 응답, 즉 메시지를 형성한다. 예를 들어, 하나의 HTTP 요청 메시지는 일반적으로 하나의 HEADERS 프레임과, 필요에 따라 여러 개의 DATA 프레임으로 구성된다.
스트림은 단일 TCP 연결 내에서 독립적인 양방향 통신 채널이다. 각 스트림은 고유한 식별자를 가지며, 하나 이상의 메시지를 교환하는 데 사용된다. 하나의 TCP 연결 안에는 여러 개의 스트림이 동시에 존재하고, 각 스트림의 프레임들은 인터리빙되어 전송된다. 이 구조가 요청/응답 다중화를 가능하게 하는 기반이 된다.
3.3. 헤더 압축 (HPACK)
3.3. 헤더 압축 (HPACK)
HTTP/1.1에서는 헤더 필드가 평문으로 반복적으로 전송되어 오버헤드가 컸다. 특히 웹 페이지 하나를 로드하는 데 수십에서 수백 개의 요청이 발생하는 현대 웹 환경에서, 중복된 헤더 데이터는 상당한 대역폭 낭비와 지연을 초래했다. HTTP/2는 이러한 비효율성을 해결하기 위해 HPACK이라는 헤더 압축 방식을 명세의 일부로 채택했다.
HPACK은 허프만 코딩과 정적/동적 테이블을 조합한 압축 방식이다. 자주 사용되는 헤더 필드(예: :method: GET, :path: /index.html)는 사전에 정의된 정적 테이블에 미리 등록되어 있다. 통신 과정에서 새롭게 등장하거나 변경된 헤더 필드는 동적 테이블에 추가되며, 이후 동일한 헤더는 테이블 내 인덱스 참조만으로 효율적으로 표현할 수 있다. 이 방식은 헤더의 중복을 제거하고 필드 이름과 값을 압축하여 전송 데이터 크기를 크게 줄인다.
HPACK은 보안 취약점으로 알려진 CRIME 공격에 대응하기 위해 설계되었다. 이전에 사용되던 DEFLATE 기반 압축은 선택적 평문 공격에 취약했으나, HPACK은 압축 컨텍스트를 송신자와 수신자 간에 명시적으로 동기화하고 허프만 코딩 테이블을 고정시킴으로써 이러한 공격 경로를 차단한다. 따라서 압축 효율을 유지하면서도 보안성을 강화한 것이 특징이다.
HPACK의 동작은 다음과 같은 원리로 요약된다.
1. 인덱싱: 헤더 필드를 정적 또는 동적 테이블의 인덱스 번호로 참조한다.
2. 리터럴 표현: 테이블에 없는 새로운 헤더는 허프만 인코딩된 리터럴 값으로 전송하며, 필요시 동적 테이블에 추가할 수 있다.
3. 테이블 관리: 동적 테이블의 크기는 제한되어 있으며, 새로운 항목이 추가될 때 가장 오래된 항목을 제거하는 FIFO 방식으로 관리된다.
이러한 설계로 인해 HTTP/2 연결에서는 동일한 헤더 필드가 반복될 경우 처음 한 번만 전송하고 이후에는 매우 작은 크기의 인덱스 참조로 대체할 수 있어, 특히 많은 수의 작은 요청을 처리할 때 네트워크 성능이 현저히 개선된다.
3.4. 서버 푸시
3.4. 서버 푸시
서버 푸시는 HTTP/2의 핵심 기능 중 하나로, 클라이언트의 요청을 기다리지 않고 서버가 능동적으로 리소스를 클라이언트에 전송할 수 있는 메커니즘이다. 이는 웹 페이지 로딩 성능을 개선하기 위해 설계되었다. 전통적인 HTTP/1.1에서는 클라이언트가 HTML 문서를 수신하고 파싱한 후, 필요한 CSS, JavaScript, 이미지 파일 등을 발견할 때마다 추가적인 요청을 보내야 했다. 서버 푸시는 이러한 추가 요청-응답 사이클을 사전에 제거함으로써 지연 시간을 줄인다.
동작 방식은 다음과 같다. 클라이언트가 주요 리소스(예: index.html)를 요청하면, 서버는 해당 요청에 대한 응답과 함께, 클라이언트가 향후 필요로 할 것으로 예상되는 추가 리소스(예: style.css, app.js)를 별도의 가상 "푸시된" 응답으로 함께 전송한다. 이때, 서버는 PUSH_PROMISE 프레임을 먼저 보내어 어떤 리소스를 푸시할 것인지 클라이언트에 알린다. 클라이언트는 이 푸시된 리소스를 자신의 캐시에 저장해 두고, 이후 실제로 해당 리소스가 필요해지면 캐시에서 즉시 사용할 수 있다.
서버 푸시를 효과적으로 활용하려면 신중한 전략이 필요하다. 과도하게 많은 리소스를 푸시하면 네트워크 대역폭을 낭비하고, 오히려 성능을 저하시킬 수 있다. 또한, 클라이언트가 이미 캐시에 가지고 있는 리소스를 중복으로 푸시하는 것을 방지해야 한다. 이를 위해 서버는 클라이언트의 캐시 상태를 고려하거나, 스마트한 휴리스틱을 적용하여 푸시할 리소스를 결정한다. 모든 주요 웹 브라우저와 서버는 이 기능을 지원하지만, 구현의 복잡성과 최적화의 어려움으로 인해 보편적으로 광범위하게 채택되지는 않았다.
이 기능은 HTTP/3에서도 개념적으로 계승되었으나, 구현 방식과 세부 사항은 프로토콜에 따라 다르다. 서버 푸시는 특히 높은 지연 시간(레이턴시)을 가진 네트워크 환경에서 페이지 로드 시간을 단축하는 데 잠재력이 큰 기술로 평가받는다.
3.5. 요청/응답 다중화
3.5. 요청/응답 다중화
HTTP/2의 요청/응답 다중화는 HTTP/1.1의 핵심적인 병목 현상을 해결하는 가장 중요한 기능 중 하나이다. 이 기능은 단일 TCP 연결 내에서 여러 개의 요청과 응답을 동시에 주고받을 수 있게 하여, HTTP/1.1의 순차적 처리 방식에서 발생하는 문제들을 극복한다.
HTTP/1.1에서는 기본적으로 하나의 연결에서 한 번에 하나의 요청과 응답만 처리할 수 있다. 여러 자원을 요청해야 할 경우, 파이프라이닝 기술이 존재했지만 헤드 오브 라인 블로킹 문제로 인해 실질적인 성능 향상이 제한적이었다[2]. 반면, HTTP/2의 다중화는 각 요청과 응답을 독립적인 스트림으로 분할하고, 이를 작은 단위의 프레임으로 쪼갠 뒤, 단일 연결 안에서 프레임들을 인터리빙하여 동시에 전송한다. 이로 인해 하나의 큰 응답이 지연되더라도 다른 스트림의 작은 응답들은 먼저 도착하여 처리될 수 있다.
이 메커니즘의 동작 방식은 다음과 같이 요약할 수 있다.
특징 | HTTP/1.1 (파이프라이닝) | HTTP/2 (다중화) |
|---|---|---|
연결 사용 | 순차적 처리, HOL 블로킹 발생 | 병렬 처리, 프레임 인터리빙 |
응답 순서 | 요청 순서와 동일하게 유지 | 요청 순서와 무관하게 도착 |
자원 차단 | 하나의 느린 응답이 전체 차단 | 느린 응답이 다른 응답을 차단하지 않음 |
프로토콜 계층 | 텍스트 기반 메시지 | 바이너리 프레임 기반 |
다중화의 주요 이점은 지연 시간 감소와 연결 효율성 향상이다. 웹 페이지는 일반적으로 HTML, CSS, 자바스크립트, 이미지 등 수십 개의 자원으로 구성된다. HTTP/1.1 환경에서는 이러한 자원을 병렬로 받기 위해 여러 개의 TCP 연결을 동시에 열어야 했지만, 이는 연결 설정 오버헤드와 운영체제 자원 소모를 초래했다. HTTP/2의 다중화는 하나의 영구 연결만으로 모든 자원을 효율적으로 전송할 수 있게 하여, 연결 수를 줄이면서도 실제 성능은 크게 향상시킨다.
4. 프로토콜 협상과 연결 설정
4. 프로토콜 협상과 연결 설정
HTTP/2는 HTTP/1.1과 완전히 다른 프로토콜이지만, 동일한 포트(80, 443)를 사용하고 기존 HTTP의 의미 체계(메서드, 상태 코드, 헤더 필드 등)를 그대로 유지한다. 따라서 클라이언트와 서버가 HTTP/2를 사용할 것인지 협상하는 과정이 필요하다. 이 협상은 주로 TLS 연결 설정 과정에서 이루어진다.
가장 일반적인 협상 방법은 ALPN(Application-Layer Protocol Negotiation)이다. ALPN은 TLS 핸드셰이크의 확장 기능으로, 클라이언트가 지원하는 애플리케이션 계층 프로토콜 목록(예: "h2", "http/1.1")을 서버에 알린다. 서버는 그 중 자신이 지원하는 가장 선호하는 프로토콜을 선택하여 응답한다. 이 협상은 암호화 연결이 설정되기 전에 완료되므로, 별도의 통신 라운드트립 없이 HTTP/2 연결을 즉시 시작할 수 있다. HTTP/2 over TLS(HTTPS)를 사용할 때는 반드시 ALPN을 통해 협상해야 한다.
평문(TLS 없이) HTTP/2 연결을 위한 협상 방법도 존재한다. 클라이언트는 Upgrade: h2c 헤더를 포함한 HTTP/1.1 요청을 보내고, 서버가 이를 지원하면 101 Switching Protocols 응답으로 프로토콜을 전환한다. 그러나 이 방법은 추가적인 라운드트립이 발생하며, 현대 웹에서는 보안상 HTTPS 사용이 권장되므로 널리 사용되지는 않는다. 대부분의 주요 브라우저와 서버는 TLS를 통한 HTTP/2만을 지원한다.
4.1. ALPN (Application-Layer Protocol Negotiation)
4.1. ALPN (Application-Layer Protocol Negotiation)
ALPN은 TLS 핸드셰이크 과정 내에서 애플리케이션 계층 프로토콜을 협상하기 위한 확장 기능이다. 이전의 NPN을 대체하여 표준화되었다. 클라이언트가 지원하는 프로토콜 목록을 ClientHello 메시지에 포함하여 전송하면, 서버는 그 목록에서 선택한 프로토콜을 ServerHello 메시지에 담아 응답한다. 이 협상은 암호화된 연결이 수립되기 전에 완료되므로 별도의 통신 라운드트립이 필요하지 않다.
HTTP/2를 암호화된 연결(HTTPS) 위에서 사용할 때, ALPN은 프로토콜 업그레이드 메커니즘을 대체하는 핵심 수단이다. 이를 통해 클라이언트와 서버는 단일 핸드셰이크 내에서 암호화 파라미터와 함께 사용할 애플리케이션 프로토콜(예: http/1.1 또는 h2)을 효율적으로 결정한다. 이는 HTTP/1.1에서 Upgrade: h2c 헤더를 사용하는 평문 연결 업그레이드 방식보다 훨씬 효율적이다.
주요 브라우저와 서버 구현체는 대부분 HTTP/2 over TLS를 사용할 때 ALPN을 필수적으로 지원한다. ALPN 협상이 실패하면, 일반적으로 양측은 이전 버전인 HTTP/1.1으로 폴백하여 통신을 진행한다.
협상 방식 | 사용 프로토콜 | 특징 |
|---|---|---|
ALPN | HTTP/2 over TLS (h2) | TLS 핸드셰이크 내에서 협상. 추가 라운드트립 없음. |
Upgrade 헤더 | HTTP/2 over cleartext (h2c) | 평문 연결에서 HTTP/1.1 요청 후 업그레이드. 추가 라운드트립 발생. |
4.2. TLS와의 관계
4.2. TLS와의 관계
HTTP/2 명세 자체는 암호화 사용을 의무화하지 않는다. 그러나 주요 웹 브라우저와 서버 구현체들은 보안과 프라이버시를 강화하기 위해 TLS를 통한 암호화된 연결 위에서만 HTTP/2를 사용하는 방향으로 사실상의 표준을 정립했다.
이러한 경향은 주로 브라우저 벤더들에 의해 주도되었다. 구글 크롬과 모질라 파이어폭스는 초기부터 평문(HTTP) 연결에서의 HTTP/2 지원을 중단하고, TLS를 사용하는 HTTPS 연결에서만 HTTP/2를 지원하기로 결정했다[3]. 이로 인해 대중적인 웹 환경에서 HTTP/2는 TLS와 밀접하게 결합된 프로토콜로 인식되게 되었다.
프로토콜 | 기본 포트 | 암호화 | 주요 브라우저의 HTTP/2 지원 여부 |
|---|---|---|---|
HTTP/1.1 | 80 | 선택 사항 | 평문, 암호화 모두 지원 |
HTTP/2 over TLS | 443 | 필수 | 지원 (주류 방식) |
HTTP/2 over TCP (평문) | 80 | 없음 | 대부분 지원하지 않음 |
이 관계는 HTTP/3에서 더욱 강화되어, QUIC 전송 프로토콜 자체에 TLS 1.3이 통합되었다. 결과적으로 현대 웹의 성능 프로토콜 진화는 보안을 전제 조건으로 삼고 진행되고 있다고 볼 수 있다.
5. 성능 향상 메커니즘
5. 성능 향상 메커니즘
HTTP/2는 바이너리 프레이밍 계층과 요청/응답 다중화 같은 기본 구조 외에도, 네트워크 자원을 더 효율적으로 관리하고 사용자 경험을 최적화하기 위한 몇 가지 중요한 메커니즘을 도입했다. 그중 핵심은 스트림 우선순위 지정과 흐름 제어이다.
스트림 우선순위 지정은 클라이언트가 서버에 여러 리소스의 상대적 중요도를 알려줄 수 있게 한다. 클라이언트는 각 스트림에 1부터 256까지의 가중치와 의존성 관계를 부여할 수 있다. 예를 들어, HTML 문서 스트림을 가장 높은 우선순위로, 그다음으로 중요한 CSS 파일을 종속시키고, 페이지 하단의 이미지들은 낮은 우선순위로 설정할 수 있다. 이를 통해 서버는 제한된 대역폭과 처리 능력 내에서 가장 중요한 리소스를 먼저 전송하여 페이지 렌더링을 가속화할 수 있다[4]. 우선순위 정보는 PRIORITY 프레임을 통해 교환된다.
흐름 제어는 TCP 연결 수준의 흐름 제어를 보완하여, 개별 스트림 수준에서 데이터 흐름을 관리하는 메커니즘이다. 이는 수신자의 처리 능력을 초과하는 데이터 전송을 방지하여 메모리 부담을 줄인다. 흐름 제어는 창 크기 기반으로 동작하며, WINDOW_UPDATE 프레임을 통해 각 스트림과 전체 연결에 대한 사용 가능한 버퍼 크기를 동적으로 조정한다. 이 메커니즘은 특히 서버 푸시 시나리오에서 유용하게 사용된다. 서버가 클라이언트가 요청하지 않은 많은 리소스를 푸시할 때, 클라이언트는 자신의 처리 속도에 맞게 창 크기를 조절하여 리소스 소비를 제어할 수 있다.
메커니즘 | 주목적 | 구현 수준 | 관련 프레임 |
|---|---|---|---|
스트림 우선순위 지정 | 중요한 리소스의 우선 전송으로 렌더링 최적화 | 스트림 |
|
흐름 제어 | 수신자 과부하 방지 및 리소스 관리 | 스트림 및 연결 |
|
이 두 메커니즘은 함께 작동하여 HTTP/1.1의 선입선출(FIFO) 방식 큐의 단점을 해소한다. 다중화된 스트림들이 무질서하게 경쟁하는 것을 방지하고, 네트워크와 클라이언트의 상태를 고려한 지능적인 자원 할당을 가능하게 한다.
5.1. 스트림 우선순위 지정
5.1. 스트림 우선순위 지정
스트림 우선순위 지정은 HTTP/2가 HTTP/1.1의 단순한 선입선출 방식에서 벗어나, 클라이언트가 서버에 여러 요청의 상대적 중요도를 알려줄 수 있게 하는 기능이다. 클라이언트는 각 스트림에 가중치(1부터 256 사이의 정수)와 종속성을 부여하여 응답이 전송되는 순서에 영향을 줄 수 있다.
이 메커니즘은 웹 페이지 로딩 성능을 최적화하는 데 목적이 있다. 예를 들어, 메인 HTML 문서는 높은 우선순위를, 이미지는 낮은 우선순위를 부여하여 사용자가 콘텐츠를 빠르게 볼 수 있도록 한다. 또는, 중요한 자바스크립트 파일이 먼저 로드된 후에야 다른 리소스가 필요하다면, 해당 파일을 부모 스트림으로 지정하고 다른 리소스를 그에 종속시킬 수 있다.
그러나 이 우선순위 힌트는 서버에 대한 '요청'일 뿐 반드시 지켜져야 하는 '명령'은 아니다. 서버는 자원 상황이나 내부 정책에 따라 우선순위를 재조정하거나 무시할 수도 있다. 이로 인해 클라이언트의 의도와 실제 서버의 응답 순서가 일치하지 않는 경우가 발생할 수 있다[5].
우선순위 정보 요소 | 설명 | 값의 범위 |
|---|---|---|
스트림 종속성 | 다른 스트림 ID를 지정하여 의존 관계를 형성한다. | 유효한 스트림 ID |
가중치 | 동일한 부모를 가진 형제 스트림 간의 상대적 중요도이다. 값이 클수록 높은 우선순위를 가진다. | 1 ~ 256 |
독점 플래그 | 지정된 종속성을 가진 기존 스트림들을 모두 새 스트림의 자식으로 재배치할지 여부를 결정한다. | 0 또는 1 |
5.2. 흐름 제어
5.2. 흐름 제어
HTTP/2의 흐름 제어는 스트림과 전체 연결 수준에서 데이터 흐름을 관리하여 수신자의 처리 능력을 초과하는 데이터 전송을 방지하는 메커니즘이다. 이는 TCP의 흐름 제어와 유사한 개념이지만, 애플리케이션 계층에서 구현되어 더 세밀한 제어를 가능하게 한다. 각 스트림은 독립적인 흐름 제어 창을 가지며, 연결 자체에도 별도의 창이 존재한다.
흐름 제어는 WINDOW_UPDATE 프레임을 통해 동작한다. 수신자는 초기 창 크기를 설정하고, 데이터를 소비하면서 송신자에게 WINDOW_UPDATE 프레임을 보내어 추가 데이터를 수신할 수 있는 용량(창 크기)을 알린다. 이를 통해 리소스가 제한된 클라이언트가 대량의 데이터를 수신하도록 강제당하는 상황을 방지하고, 메모리 부족을 예방할 수 있다. 흐름 제어는 송신자가 수신자의 처리 속도를 따라가지 못하도록 방지하는 혼잡 제어와는 목적이 다르다.
흐름 제어 창의 크기는 설정에 따라 조정될 수 있다. 클라이언트와 서버는 SETTINGS 프레임을 교환하여 초기 흐름 제어 창 크기를 협상할 수 있다. 또한, 특정 스트림이나 전체 연결에 대해 WINDOW_UPDATE 프레임을 보내어 동적으로 창 크기를 증가시킬 수 있다. 이 메커니즘은 특히 서버 푸시 시나리오에서 유용하게 작동한다. 서버가 클라이언트가 요청하지 않은 리소스를 푸시하기 전에, 클라이언트의 수용 여부와 능력을 이 흐름 제어를 통해 확인할 수 있기 때문이다.
제어 대상 | 설명 | 관련 프레임 |
|---|---|---|
스트림 수준 흐름 제어 | 개별 스트림의 데이터 흐름을 제어한다. |
|
연결 수준 흐름 제어 | 전체 HTTP/2 연결의 데이터 흐름을 제어한다. |
|
초기 창 크기 설정 | 흐름 제어의 시작 용량을 협상한다. |
|
이러한 세분화된 흐름 제어는 HTTP/1.1의 선입선출(FIFO) 방식의 큐 모델에서는 제공할 수 없었던 기능이다. HTTP/1.1에서는 단일 연결 내에서 요청과 응답이 순차적으로 처리되기 때문에, 느린 응답 하나가 뒤따르는 모든 응답을 막는 Head-of-line 블로킹 문제가 발생할 수 있었다. HTTP/2의 흐름 제어는 다중화된 스트림 환경에서 각 데이터 흐름을 효율적으로 관리함으로써 이러한 문제를 완화하고 자원을 보다 공정하게 배분하는 데 기여한다.
6. HTTP/2 vs HTTP/1.1 비교
6. HTTP/2 vs HTTP/1.1 비교
HTTP/2는 HTTP/1.1의 한계를 해결하고 웹 성능을 개선하기 위해 설계되었다. 두 프로토콜의 근본적인 차이는 데이터 전송 방식에 있다. HTTP/1.1은 텍스트 기반의 프로토콜로, 요청과 응답을 줄 단위의 평문으로 주고받는다. 반면 HTTP/2는 효율성을 높이기 위해 바이너리 프레이밍 계층을 도입하여 모든 통신을 바이너리 형식의 프레임으로 캡슐화한다. 이 변경은 파싱 속도를 높이고 오류 발생 가능성을 줄인다.
가장 두드러진 성능 차이는 연결 처리 방식에서 나타난다. HTTP/1.1에서는 하나의 TCP 연결 당 한 번에 하나의 요청/응답만 처리할 수 있어, 여러 자원을 받기 위해 브라우저는 여러 개의 병렬 연결을 열거나 HTTP 파이프라이닝을 사용해야 했다. 파이프라이닝은 HOL 블로킹 문제로 인해 실질적인 성능 향상에 한계가 있었다. HTTP/2는 단일 연결 내에서 요청/응답 다중화를 지원하여 여러 스트림이 동시에 전송되고 응답될 수 있도록 한다. 이를 통해 HOL 블로킹 문제를 해결하고 연결 효율성을 극대화한다.
비교 항목 | HTTP/1.1 | HTTP/2 |
|---|---|---|
프로토콜 형식 | 텍스트(평문) | 바이너리 |
연결 방식 | 기본적으로 단일 요청/응답 처리, 병렬 연결 필요 | 단일 연결 내 다중화 지원 |
헤더 데이터 | 압축되지 않은 평문 반복 전송 | HPACK 알고리즘을 사용한 효율적 압축 |
서버 개시 작업 | 클라이언트 요청에만 응답 가능 | 서버 푸시를 통해 사전에 리소스 전송 가능 |
자원 의존성 관리 | 제한적 | 스트림 우선순위 지정을 통한 명시적 관리 |
또한, 헤더 압축 방식에서 큰 차이를 보인다. HTTP/1.1에서는 매 요청마다 중복된 헤더 필드(예: User-Agent, Cookie)를 반복적으로 보내야 하여 오버헤드가 컸다. HTTP/2는 HPACK 압축 방식을 사용하여 헤더 크기를 크게 줄인다. HPACK은 정적/동적 테이블을 활용해 헤더 필드를 인덱싱하고, 허프만 코딩을 적용하여 데이터를 압축한다. 이는 특히 작은 요청이 빈번한 모바일 환경에서 큰 성능 이점을 제공한다.
마지막으로, 능동적인 리소스 전송 기능에서 차이가 있다. HTTP/1.1은 순수한 요청-응답 모델을 고수한다. 반면 HTTP/2는 서버 푸시 기능을 도입했다. 서버는 클라이언트가 특정 리소스(예: HTML 페이지)를 요청했을 때, 해당 리소스와 연관된 추가 리소스(예: CSS, JavaScript 파일)를 클라이언트의 명시적 요청 없이도 미리 푸시할 수 있다. 이는 예측 가능한 리소스에 대한 왕복 시간을 제거하여 페이지 로딩 지연을 줄이는 데 기여한다.
7. 구현 및 배포 현황
7. 구현 및 배포 현황
HTTP/2는 2015년 RFC 7540으로 표준화된 이후, 주요 웹 브라우저와 서버 소프트웨어에서 빠르게 지원되기 시작했다. 초기에는 TLS 암호화 연결을 통해서만 지원하는 경우가 많았으나, 이후 비암호화 연결에서도 사용할 수 있도록 확장되었다. 현재 대부분의 최신 웹 인프라는 HTTP/2를 기본 또는 권장 프로토콜로 채택하고 있다.
주요 웹 브라우저의 지원 현황은 다음과 같다.
브라우저 | 최초 지원 버전 | 지원 시작 연도 | 비고 |
|---|---|---|---|
41 | 2015 | ||
36 | 2015 | ||
12 | 2015 | 인터넷 익스플로러는 지원하지 않음 | |
9 | 2016 | ||
28 | 2015 |
서버 측에서는 아파치 HTTP 서버, NGINX, 마이크로소프트 IIS 등 주요 웹 서버 소프트웨어가 모듈 형태로 HTTP/2를 지원한다. 예를 들어, 아파치는 mod_http2 모듈을, NGINX는 ngx_http_v2_module을 통해 지원한다. 많은 CDN과 클라우드 서비스 제공업체들도 기본적으로 HTTP/2를 활성화하여 서비스를 제공하고 있다.
도입 시에는 몇 가지 고려사항이 있다. 첫째, TLS 암호화가 필수는 아니지만, 대부분의 브라우저 구현체가 보안 연결을 통해서만 HTTP/2를 사용하도록 설정되어 있어 사실상 HTTPS가 전제 조건이 되었다. 둘째, 기존 HTTP/1.1 환경에 최적화된 특정 최적화 기법(예: 도메인 샤딩, 스프라이트 이미지, 코드 합치기)이 HTTP/2에서는 오히려 성능을 저하시킬 수 있어 재평가가 필요하다. 셋째, 네트워크 중간 장비(프록시, 방화벽, 로드 밸런서) 중에서 HTTP/2의 바이너리 프레이밍을 제대로 이해하지 못해 연결을 방해하는 경우가 있을 수 있어 테스트가 중요하다.
7.1. 주요 브라우저 및 서버 지원
7.1. 주요 브라우저 및 서버 지원
HTTP/2는 2015년 표준화 이후 주요 웹 브라우저와 웹 서버 소프트웨어에서 빠르게 지원이 확산되었다. 초기에는 TLS 암호화를 필수로 요구하는 브라우저 구현이 있었으나, 이후 명세에 맞춰 비암호화 연결도 지원하게 되었다.
주요 브라우저의 HTTP/2 지원 현황은 다음과 같다.
브라우저 | 최초 지원 버전 | 지원 시작 연도 | 비고 |
|---|---|---|---|
Chrome 41 | 2015 | ||
Firefox 36 | 2015 | ||
Edge 12 | 2015 | 인터넷 익스플로러는 지원하지 않음 | |
Safari 9 | 2015 | ||
Opera 28 | 2015 |
서버 측에서는 Nginx가 1.9.5 버전(2015년)부터, 아파치 HTTP 서버가 2.4.17 버전(2015년)부터 공식 모듈을 통해 HTTP/2를 지원하기 시작했다. Node.js는 8.4.0 버전(2017년)부터 실험적 지원을, 10.0.0 버전부터 안정적으로 지원한다. 클라우드 플랫폼과 CDN 제공업체들도 대부분 2016년 전후로 서비스에 HTTP/2를 통합했다.
도입 시 고려사항으로는, TLS 인증서 설정이 필수는 아니지만 대부분의 최적화된 환경에서 암호화 연결을 사용한다는 점, 기존 HTTP/1.1 애플리케이션과의 호환성을 유지하면서 점진적으로 전환할 수 있다는 점, 그리고 서버 푸시와 같은 특정 기능의 구현과 활용 수준이 플랫폼에 따라 다를 수 있다는 점 등이 있다.
7.2. 도입 시 고려사항
7.2. 도입 시 고려사항
HTTP/2 도입은 대부분의 경우 성능 향상을 가져오지만, 특정 환경이나 구성에서는 주의 깊게 검토해야 할 사항이 존재합니다.
네트워크 환경과 프록시 서버의 호환성 문제가 주요 고려사항입니다. 특히 중간에 위치한 오래되거나 비준수적인 프록시가 바이너리 프레이밍을 처리하지 못하거나, 다중화된 스트림을 제대로 전달하지 못할 경우 연결 오류나 성능 저하를 초래할 수 있습니다. 이는 TLS 암호화를 사용할 때 더 두드러지는 문제입니다[6]. 서버 측에서는 HTTP/2를 지원하는 웹 서버 소프트웨어(예: Nginx, Apache)의 적절한 버전과 모듈 구성이 필요합니다.
애플리케이션 수준의 최적화 전략도 재평가해야 합니다. HTTP/1.1의 성능 한계를 극복하기 위해 널리 사용되던 도메인 샤딩, 이미지 스프라이트, 코드 합치기 등의 기법은 HTTP/2 환경에서는 불필요하거나 오히려 성능을 해칠 수 있습니다. 예를 들어, 불필요한 도메인 샤딩은 추가적인 TCP 연결 설정과 TLS 핸드셰이크를 유발하여 오버헤드를 증가시킵니다. 따라서 기존 최적화 기법의 효과를 측정하고 조정하는 작업이 수반되어야 합니다.
고려사항 | 설명 | 권장 조치 |
|---|---|---|
중간자(프록시) 호환성 | 오래된 프록시가 바이너리 프레임을 처리하지 못해 연결 실패 가능성 | 모니터링 강화, 점진적 롤아웃, TLS 사용 시 주의 |
서버 리소스 | 다중화된 연결로 인해 서버당 동시 처리 연결 수 증가 가능 | 서버의 메모리 및 CPU 용량 계획 수립, 연결 제한 설정 검토 |
클라이언트 지원 | 모든 사용자 에이전트(브라우저)가 HTTP/2를 지원하지는 않음 | ALPN을 통한 협상으로 HTTP/1.1 대체 연결 제공 유지 |
기존 최적화 기법 | 도메인 샤딩 등 HTTP/1.1용 기법이 역효과를 낼 수 있음 | 성능 측정을 통해 기법의 지속 필요성 평가 및 제거 |
8. HTTP/3와의 관계 및 발전 방향
8. HTTP/3와의 관계 및 발전 방향
HTTP/2는 HTTP/1.1의 주요 성능 문제를 해결했지만, 여전히 TCP 프로토콜에 기반하고 있다는 근본적인 한계를 지녔다. TCP의 혼잡 제어 및 순서 보장 메커니즘은 신뢰성은 높지만, 패킷 손실 시 발생하는 HOL 블로킹 문제가 여전히 존재했다. 이러한 제약을 극복하기 위해 설계된 차세대 프로토콜이 HTTP/3이다.
HTTP/3의 가장 큰 변화는 하위 전송 계층 프로토콜을 TCP에서 QUIC으로 전환한 점이다. QUIC은 UDP 위에 구축된 새로운 전송 프로토콜로, 다중화된 스트림을 네이티브로 지원한다. 이로 인해 한 스트림에서 패킷 손실이 발생해도 다른 스트림에 영향을 미치지 않아 HOL 블로킹 문제가 근본적으로 해소된다. 또한 연결 설정 시 TLS 핸드셰이크와 QUIC의 핸드셰이크를 결합하여 초기 연결 지연을 크게 단축했다.
두 프로토콜의 발전 관계를 요약하면 다음과 같다.
특성 | HTTP/2 | HTTP/3 |
|---|---|---|
전송 프로토콜 | ||
핸드셰이크 | ||
HOL 블로킹 | TCP 수준에서 발생 | 스트림 수준에서 격리되어 발생하지 않음 |
연결 이전 | IP/포트 변경 시 연결 재설정 필요 | 연결 ID를 사용하여 네트워크 변경 시 연결 유지 |
HTTP/3는 HTTP/2의 핵심 기능인 바이너리 프레이밍, 헤더 압축, 스트림 개념 등을 계승하면서, 더 빠르고 유연한 전송 계층을 도입했다. 현재 주요 웹 브라우저와 CDN, 서버 소프트웨어는 점차 HTTP/3 지원을 확대하고 있다. 이는 웹 프로토콜의 진화가 단순한 기능 추가를 넘어, 네트워크 환경의 다양성과 모바일 사용 증가에 대응하는 근본적인 아키텍처 개선으로 나아가고 있음을 보여준다.
