HTTP/1.1 vs HTTP/2: 웹 성능 혁신의 이야기
🚀 들어가며
웹사이트를 방문할 때 로딩 속도가 빠른 사이트와 느린 사이트를 경험해본 적이 있으실 겁니다. 이러한 차이의 핵심에는 HTTP 프로토콜이 있습니다. 오늘은 웹의 성능을 크게 개선한 HTTP/2가 기존 HTTP/1.1과 어떻게 다른지, 그리고 왜 이런 변화가 필요했는지 자세히 알아보겠습니다.
📚 HTTP 프로토콜의 역사
HTTP의 시작
HTTP(HyperText Transfer Protocol)는 1990년 팀 버너스리가 월드 와이드 웹을 만들면서 함께 탄생했습니다.
주요 버전별 발전사:
- HTTP/0.9(1991): 단일 GET만.
- HTTP/1.0(1996): 헤더·상태 코드·POST 등장.
- HTTP/1.1(1997): Keep-Alive·캐싱·파이프라이닝.
- HTTP/2(2015→2022 재발행 RFC 9113): 바이너리 프레이밍, 멀티플렉싱, HPACK 도입. RFC Editor+1
- HTTP/3(2022): UDP 기반 QUIC 위에서 HTTP 동작. 헤더 압축은 QPACK. RFC EditorIETF Datatracker참고: HTTP/2는 텍스트가 아닌 바이너리 프레이밍을 쓰고, 하나의 연결에서 여러 요청을 동시에 흘려보낼 수 있어요. Apache HTTP Server
HTTP/1.1의 시대와 한계
HTTP/1.1은 18년간 웹의 표준으로 자리잡았습니다. 하지만 웹이 발전하면서 한계가 드러나기 시작했습니다.
1990년대 웹페이지 vs 2010년대 웹페이지:
1990년대:
- 평균 페이지 크기: 2KB
- 리소스 개수: 1-3개
- 대부분 텍스트와 간단한 이미지
2010년대:
- 평균 페이지 크기: 2MB+
- 리소스 개수: 100개 이상
- CSS, JavaScript, 이미지, 폰트, API 호출 등
🔍 HTTP/1.1의 한계점
1. Head-of-Line Blocking (HOL Blocking)
가장 심각한 문제는 대기줄 문제였습니다.
🚗 HTTP/1.1 = 단일 차선 도로
[요청1] → [요청2] → [요청3] → [요청4]
↓
요청1이 지연되면 뒤의 모든 요청이 대기!
실제 예시:
GET /index.html ← 5초 지연
GET /style.css ← 대기 중...
GET /script.js ← 대기 중...
GET /image.jpg ← 대기 중...
2. 연결 제한
브라우저는 도메인당 최대 6-8개의 동시 연결만 허용했습니다.
도메인: example.com
연결1: [HTML] [CSS] [JS]
연결2: [Image1] [Image2] [Image3]
연결3: [Font1] [Font2] [API1]
연결4: [API2] [API3] [Video]
연결5: [Icon1] [Icon2] [Banner]
연결6: [Ad1] [Ad2] [Analytics]
연결7: 대기 중... ⏳
연결8: 대기 중... ⏳
3. 헤더 중복
매 요청마다 동일한 헤더를 반복 전송했습니다.
# 첫 번째 요청
GET /index.html HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 Chrome/91.0.4472.124
Accept: text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language: ko-KR,ko;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate, br
Cookie: session=abc123; user_id=456; theme=dark
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# 두 번째 요청 (거의 동일한 헤더!)
GET /style.css HTTP/1.1
Host: example.com ← 중복
User-Agent: Mozilla/5.0 Chrome/91.0.4472.124 ← 중복
Accept: text/css,*/*;q=0.1
Accept-Language: ko-KR,ko;q=0.9,en;q=0.8 ← 중복
Accept-Encoding: gzip, deflate, br ← 중복
Cookie: session=abc123; user_id=456; theme=dark ← 중복
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ← 중복
🎯 HTTP/2 탄생 배경
Google의 SPDY 프로젝트
2009년, 구글은 웹 성능 개선을 위해 SPDY 프로토콜을 개발했습니다.
SPDY의 주요 혁신:
- 멀티플렉싱 지원
- 헤더 압축
- 서버 푸시 (요즘은 브라우저에서 해당 push 권한을 비활성화 하고 있습니다.)
- 우선순위 제어
HTTP/2 표준화
SPDY의 성공을 바탕으로 2012년 HTTP/2 표준화 작업이 시작되었습니다.
주요 목표:
- 지연 시간 감소: 페이지 로딩 속도 향상
- 네트워크 효율성: 대역폭 사용량 최적화
- 하위 호환성: 기존 웹 애플리케이션과 호환
- 보안 강화: HTTPS 기본 사용
⚡ HTTP/2의 혁신적 기능들
1. 바이너리 프로토콜
HTTP/1.1 (텍스트 기반):
GET /api/users HTTP/1.1\r\n
Host: api.example.com\r\n
Accept: application/json\r\n
\r\n
HTTP/2 (바이너리 기반):
바이너리 프레임:
+-------+------+------+--------+--------+
|Length | Type |Flags |Stream ID|Payload |
+-------+------+------+--------+--------+
| 24bit | 8bit |8bit | 31bit |Variable|
+-------+------+------+--------+--------+
장점:
- 파싱 속도 향상
- 에러 발생률 감소
- 압축 효율성 증대
2. 멀티플렉싱 (Multiplexing)
HTTP/1.1의 순차 처리:
타임라인:
0ms 200ms 400ms 600ms 800ms
|--HTML--|
|--CSS---|
|--JS----|
|--IMG--|
HTTP/2의 동시 처리:
타임라인:
0ms 200ms 400ms
|--HTML--|
|--CSS---|
|--JS----|
|--IMG1--|
|--IMG2--|
|--IMG3--|
실제 구현 예시:
// HTTP/1.1: 순차적 로딩
async function loadResourcesHTTP1() {
const html = await fetch('/index.html');
const css = await fetch('/style.css'); // HTML 완료 후
const js = await fetch('/script.js'); // CSS 완료 후
const img = await fetch('/image.jpg'); // JS 완료 후
}
// HTTP/2: 병렬 로딩
async function loadResourcesHTTP2() {
const [html, css, js, img] = await Promise.all([
fetch('/index.html'),
fetch('/style.css'), // 동시 시작
fetch('/script.js'), // 동시 시작
fetch('/image.jpg') // 동시 시작
]);
}
※ Stream은 물리적 구멍(소켓)은 하나지만, 프레임마다 붙은 Stream ID 덕분에 서버는 패킷을 받아서 “이건 Stream 5, 저건 Stream 9”처럼 디멀티플렉싱합니다. 한 연결에서 수백 개의 스트림이 동시에 열릴 수 있습니다.
3. HPACK 헤더 압축
압축 전 (HTTP/1.1):
GET /api/users HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: application/json, text/plain, */*
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Accept-Encoding: gzip, deflate, br
Cookie: sessionId=abc123def456; userId=789; theme=dark; language=ko
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Cache-Control: no-cache
Pragma: no-cache
총 크기: ~800 바이트
압축 후 (HTTP/2 + HPACK):
동적 테이블 참조:
:method: GET
:path: /api/users
:authority: api.example.com
[다른 헤더들은 인덱스로 참조]
총 크기: ~80 바이트 (90% 압축!)
4. 서버 푸시 (Server Push)
이 방식은 요즘 사용하지 않습니다.
기존 방식 (HTTP/1.1):
클라이언트 → 서버: GET /blog/post/123
서버 → 클라이언트: [HTML 내용]
클라이언트가 HTML 파싱 후...
클라이언트 → 서버: GET /css/blog.css
서버 → 클라이언트: [CSS 내용]
클라이언트 → 서버: GET /js/comments.js
서버 → 클라이언트: [JS 내용]
총 3번의 왕복 (Round Trip)
HTTP/2 서버 푸시:
클라이언트 → 서버: GET /blog/post/123
서버의 응답:
1. PUSH_PROMISE: /css/blog.css 푸시 예고
2. PUSH_PROMISE: /js/comments.js 푸시 예고
3. DATA: [HTML 내용]
4. DATA: [CSS 내용] - 푸시
5. DATA: [JS 내용] - 푸시
총 1번의 왕복으로 모든 리소스 전송!
5. 스트림 우선순위
우선순위 트리 구조:
HTML 문서 (가중치: 256) - 최우선
├─ CSS 파일 (가중치: 220) - 렌더링 차단 리소스
│ ├─ critical.css (가중치: 200)
│ └─ layout.css (가중치: 100)
├─ JavaScript (가중치: 220) - 인터랙션 필수
│ ├─ framework.js (가중치: 180)
│ └─ analytics.js (가중치: 20)
└─ 이미지 (가중치: 8) - 점진적 로딩
├─ hero-image.jpg (가중치: 64)
├─ content-images (가중치: 16)
└─ ads-images (가중치: 1)
6. HTTPS 기본 사용
HTTP/2 - Wikipedia
From Wikipedia, the free encyclopedia Version 2 of the Hypertext Transfer Protocol used by the World Wide Web HTTP/2 (originally named HTTP/2.0) is a major revision of the HTTP network protocol used by the World Wide Web. It was derived from the earlier ex
en.wikipedia.org
HTTP2.0 에서는 모든 브라우저들이 HTTPS(TLS)를 사용 해야만 HTTP2가 동작하도록 설정 되어있습니다.
https://httpd.apache.org/docs/2.4/howto/http2.html
HTTP/2 guide - Apache HTTP Server Version 2.4
HTTP/2 guide This is the howto guide for the HTTP/2 implementation in Apache httpd. This feature is production-ready and you may expect interfaces and directives to remain consistent releases. HTTP/2 is the evolution of the world's most successful applicat
httpd.apache.org
Apache 문서에 나와 있지만, HTTP 통신을 하게되면 h2c를 통해서 HTTP2.0을 사용할 수 있다고 명시 되어 있지만, 브라우저는 h2(TLS)만 씁니다. 그래서 “브라우저 환경에서는 사실상 TLS 필수”라고합니다.
HTTPS 통신을 하지 않는 서버같은 경우에는 강제로 HTTP1.1을 사용하게 됩니다.
6. 103 Early Hints
103 Early Hints는 최종 응답(200/302 등)을 만들기 전에 서버가 미리 “이 리소스들부터 받아두세요”라고 힌트를 보내는 정보(Informational) 상태 코드입니다. 브라우저는 이걸 받자마자 preload/preconnect를 시작할 수 있어 초기 지연을 줄입니다. IETF DatatrackerChrome for Developers
간단한 흐름
서버 ──▶ 103 Early Hints
Link: </css/critical.css>; rel=preload; as=style
Link: </js/app.js>; rel=preload; as=script
(브라우저는 위 리소스를 미리 받기 시작)
서버 ──▶ 200 OK + HTML 본문
Server Push와 뭐가 다른가?
누가 전송 결정을 하나 | 브라우저 (힌트만 받고 스스로 판단) | 서버 (클라이언트가 요청 전 강제 전송) |
중복/캐시 고려 | 한다 – 캐시 있으면 네트워크 안 씀 | 어려움 – 이미 캐시가 있어도 서버가 밀면 내려옴 |
우선순위/취소 | 브라우저가 재우선화/취소 가능 | 제한적 – 이미 푸시 스트림이 흐르는 중엔 낭비 발생 |
현재 브라우저 지원 | 현행 추천 (h2/h3에서 효과) | 사실상 퇴출 (주요 브라우저·서버 비활성/제거) |
운영 난이도 | 낮음 (헤더 몇 줄/프록시·CDN 지원) | 높음 (중복·낭비·우선순위 충돌 관리가 어려움) |
요약: Early Hints는 “이거 곧 쓸 것 같아”라는 신호이고, 브라우저 스케줄러가 캐시/정책/우선순위를 따져서 필요한 것만, 필요한 만큼 받습니다. Server Push는 과거에 서버가 강제로 데이터를 밀던 방식이라 낭비·충돌이 많아졌고 지금은 거의 쓰지 않습니다.
🔧⚠️ 주의사항과 한계
1. TCP 레벨 HOL Blocking
HTTP/2도 TCP 레벨에서는 여전히 Head-of-Line Blocking이 발생할 수 있습니다. (TCP 통신에는 기본적으로 순서 보장을 원칙으로 통신하기 때문에.)
TCP 패킷 레벨:
패킷1 [손실] → 전체 스트림 대기
패킷2 [대기]
패킷3 [대기]
패킷4 [대기]
🚀 HTTP/3과 미래
QUIC 프로토콜
HTTP/3는 UDP 기반의 QUIC 프로토콜을 사용하여 TCP의 한계를 극복합니다.
주요 개선사항:
- 0-RTT 재개(Resumption): 과거 세션 티켓이 있을 때 추가 왕복 없이(TCP 3-way+TLS 핸드셰이크 없음) 데이터를 바로 보내기 시작할 수 있어 초기 지연을 줄입니다. 다만 재전송(Replay) 위험이 있어 안전한(idempotent) 요청에 한정해 써야 합니다. IETF Datatracker+1
- 연결 마이그레이션: 클라이언트가 IP/네트워크가 바뀌어도(Wi-Fi→LTE 등) 같은 QUIC 연결을 유지할 수 있습니다. QUIC v1에서 능동 마이그레이션은 클라이언트만 수행(서버는 Preferred Address 제안 가능). IETF Datatracker
- 내장 암호화: QUIC은 TLS 1.3을 프로토콜에 통합(핸드셰이크 결합)해서 낮은 RTT로 보안 연결을 수립합니다. QUIC
- QPACK(HTTP/3 헤더 압축): HTTP/2의 HPACK이 만들던 헤더-기반 HoL 블로킹을 줄이도록 설계된 HTTP/3 전용 헤더 압축입니다(동적 테이블 업데이트를 별도 스트림으로 분리, 의존성 신호화). IETF Datatracker
참고: HTTP/3 자체(HTTP/2 대비) 정의는 RFC 9114에, QUIC 전송은 RFC 9000에 있습니다. IETF Datatracker+1
'프로그래밍 > 웹, 네트워크' 카테고리의 다른 글
X-Forwarded-For(XFF) 헤더란? (2) | 2023.05.01 |
---|---|
DNS Record란? (0) | 2021.06.28 |
ARP통신에 대해서... (1) | 2021.06.16 |
DNS에 대한 설명(디테일 하게....) (7) | 2021.03.29 |
Web Server과 WAS의 차이점(MVC 모델링) 기초부터 설명해욧~ (1) | 2020.11.08 |
댓글