OneWebDesk

HTTP/1.1 vs HTTP/2 vs HTTP/3: 차이와 적용 방법

멀티플렉싱·헤더 압축·QUIC까지 버전별 차이를 정리하고 내 서버에 적용·확인하는 방법.

같은 HTML·CSS·이미지를 내려받아도 HTTP 버전에 따라 페이지가 뜨는 속도는 크게 달라집니다. HTTP/1.1은 1997년 설계 그대로 요청을 한 줄로 세워 처리하고, HTTP/2는 하나의 연결에서 수십 개 요청을 동시에 실어 나르며, HTTP/3는 아예 TCP를 버리고 QUIC(UDP 기반)으로 갈아탔습니다. 이 글은 세 버전이 정확히 무엇이 다른지, 왜 달라졌는지, 그리고 내 서버에 HTTP/2·HTTP/3를 켜고 확인하는 방법까지 정리합니다.

지금 내 사이트가 어떤 버전으로 응답하는지 궁금하다면 먼저 HTTP/2·HTTP/3 지원 확인 도구로 도메인을 넣어보세요. 결과를 보고 나서 아래 내용을 읽으면 훨씬 빠르게 이해됩니다.

HTTP/1.1의 세 가지 한계

HTTP/1.1이 느린 이유는 크게 세 가지입니다.

  • 연결당 요청 1개 + 브라우저 연결 6개 제한 — HTTP/1.1은 하나의 TCP 연결에서 한 번에 요청 하나만 처리합니다(응답이 와야 다음 요청). 그래서 브라우저는 도메인당 TCP 연결을 6개까지 열어 병렬화하지만, 리소스가 수십 개인 현대 페이지에서는 턱없이 부족합니다.
  • HOL(Head-of-Line) 블로킹 — 앞선 요청의 응답이 느리면(예: 큰 이미지) 같은 연결의 뒤 요청들이 전부 대기합니다. 파이프라이닝이 스펙에는 있었지만 이 문제 때문에 사실상 아무 브라우저도 쓰지 않았습니다.
  • 텍스트 헤더의 반복 전송Cookie, User-Agent 같은 헤더가 요청마다 평문으로 통째로 다시 전송됩니다. 쿠키가 큰 사이트라면 요청 하나에 수 KB씩 낭비됩니다.

이 한계를 우회하려고 나온 편법이 도메인 샤딩(정적 자원을 img1.example.com, img2.example.com으로 쪼개 연결 수를 늘리기), CSS 스프라이트, JS/CSS 통합 번들이었습니다. 뒤에서 다루지만 이 기법들은 HTTP/2에서는 오히려 성능을 해치는 안티패턴이 됩니다.

HTTP/2 — 하나의 TCP 연결, 여러 스트림

2015년 표준화된 HTTP/2의 핵심 변화는 네 가지입니다.

  • 바이너리 프레이밍 — 텍스트 프로토콜을 버리고 요청·응답을 작은 바이너리 프레임으로 쪼갭니다. 파싱이 빠르고 모호함이 없습니다.
  • 멀티플렉싱 — 하나의 TCP 연결 위에 여러 스트림을 만들어 요청 수십 개를 동시에 주고받습니다. 연결 6개 제한, 요청 줄 세우기가 한 번에 해결됩니다.
  • HPACK 헤더 압축 — 이미 보낸 헤더는 인덱스 번호로 대체합니다. 두 번째 요청부터는 쿠키·UA를 다시 보내지 않아 헤더 크기가 수 KB에서 수십 바이트로 줄어듭니다.
  • 우선순위 지정 — CSS·폰트처럼 렌더링을 막는 리소스를 이미지보다 먼저 받도록 스트림에 가중치를 줄 수 있습니다.

다만 남은 약점이 있습니다. 스트림은 여러 개지만 TCP 연결은 하나라서, 패킷 하나가 유실되면 TCP가 그 패킷을 재전송받을 때까지 뒤에 도착한 모든 스트림의 데이터가 커널 버퍼에서 대기합니다. 애플리케이션 계층의 HOL 블로킹은 없앴지만 전송(TCP) 계층의 HOL 블로킹은 그대로라는 뜻입니다. 유선 환경에서는 문제가 안 되지만, 패킷 손실이 잦은 모바일 망에서는 HTTP/2가 HTTP/1.1(연결 6개가 서로 독립)보다 오히려 느려지는 역전도 생깁니다.

HTTP/3 — QUIC이 TCP를 대체하다

HTTP/3(2022년 RFC 9114)는 이 마지막 문제를 풀기 위해 전송 계층 자체를 바꿨습니다. TCP 대신 UDP 위에 구현된 QUIC을 사용합니다.

  • 스트림별 독립 손실 복구 — QUIC은 스트림을 전송 계층에서 이해합니다. 패킷이 유실되면 그 패킷에 실린 스트림만 기다리고 나머지 스트림은 그대로 진행합니다. TCP HOL 블로킹이 사라집니다.
  • 핸드셰이크 단축과 0-RTT — TCP+TLS 1.3은 첫 연결에 왕복 2회(RTT)가 필요하지만 QUIC은 전송·암호화 협상을 합쳐 1-RTT로 끝냅니다. 재방문이라면 이전 세션 정보로 0-RTT, 즉 첫 패킷에 요청을 실어 보낼 수 있습니다.
  • 연결 마이그레이션 — TCP 연결은 IP:포트 4튜플로 식별되어 와이파이에서 LTE로 바뀌면 끊어지지만, QUIC은 연결 ID로 식별하므로 네트워크가 바뀌어도 다운로드가 이어집니다.
  • QPACK 헤더 압축 — HPACK을 QUIC의 순서 독립 스트림에 맞게 고친 버전입니다.

비교표와 실전 예시: 리소스 30개 페이지

항목HTTP/1.1HTTP/2HTTP/3
전송 계층TCPTCPQUIC (UDP)
멀티플렉싱없음 (연결 6개로 우회)스트림 다중화스트림 다중화
HOL 블로킹요청 단위 (심함)TCP 계층에 잔존사실상 없음
첫 연결 핸드셰이크2~3 RTT (TCP+TLS)2 RTT (TCP+TLS 1.3)1 RTT, 재방문 0-RTT
헤더 압축없음 (평문)HPACKQPACK
네트워크 전환(WiFi→LTE)연결 끊김연결 끊김연결 유지 (마이그레이션)

예시 계산 — CSS 2개, JS 5개, 이미지 23개, 총 30개 리소스를 RTT 50ms 환경에서 받는다고 해봅시다. HTTP/1.1에서는 연결 6개로 나눠 받으므로 최소 5배치(30÷6)가 순차 진행되고, 배치마다 최소 1 RTT씩 걸려 리소스 대기만 250ms 이상, 여기에 연결 6개 각각의 TCP+TLS 핸드셰이크 비용이 더해집니다. HTTP/2에서는 이미 열린 연결 하나로 30개 요청을 한 번에 보내고 응답이 병렬로 흘러들어오므로, 이론상 가장 큰 리소스 하나의 다운로드 시간 + 1 RTT 수준으로 줄어듭니다. 실제 차이는 응답 속도 측정 도구로 같은 URL의 TTFB·전체 응답 시간을 재보면 체감할 수 있습니다.

내 서버에 켜는 법과 확인 방법

HTTP/2 켜기 (nginx) — 사실상 HTTPS가 전제 조건입니다(브라우저가 h2를 TLS에서만 협상).

  • 구버전 nginx: listen 443 ssl http2;
  • nginx 1.25.1 이상: listen 443 ssl; 아래에 http2 on; (listen 플래그 방식은 deprecated)
  • Apache는 Protocols h2 http/1.1, 대부분의 CDN(Cloudflare 등)은 기본 활성화

HTTP/3 켜기 — 조건이 조금 더 까다롭습니다.

  1. nginx 1.25 이상(QUIC 지원 빌드) 또는 HTTP/3를 지원하는 CDN 사용
  2. listen 443 quic reuseport; + http3 on; 추가 (기존 listen 443 ssl;과 병행)
  3. 브라우저에게 h3를 광고하는 Alt-Svc 응답 헤더 추가: add_header Alt-Svc 'h3=":443"; ma=86400';
  4. 방화벽·보안그룹에서 UDP 443 인바운드 오픈 — 가장 흔한 실수가 TCP 443만 열어두는 것

브라우저는 첫 접속은 HTTP/2로 하고, 응답의 Alt-Svc 헤더를 보고 다음 요청부터 HTTP/3로 전환합니다. 이 헤더가 실제로 내려오는지는 HTTP 헤더 조회 도구로 확인하고, 최종적으로 프로토콜 협상이 되는지는 HTTP/2·HTTP/3 지원 확인으로 검증하세요.

HTTP/2 시대의 안티패턴 정리 — 1.1 시절 최적화는 이제 역효과입니다.

  • 도메인 샤딩 — 연결이 하나면 충분한데 도메인을 쪼개면 DNS 조회·TCP/TLS 핸드셰이크만 늘고 HPACK 압축 문맥도 도메인별로 갈라집니다. 자원을 한 도메인으로 모으세요.
  • 거대 번들·스프라이트 — 파일 하나에 몰아넣으면 아이콘 하나만 바뀌어도 전체 캐시가 무효화됩니다. 멀티플렉싱 덕에 작은 파일 여러 개의 요청 비용이 거의 없으므로, 적당한 단위로 나누고 캐시 수명을 길게 가져가는 편이 낫습니다.
  • 인라인 몰아넣기 — Critical CSS 정도는 유효하지만, 캐시 가능한 자원까지 HTML에 인라인하면 재방문 성능을 잃습니다.

자주 묻는 질문

HTTP/2만 적용해도 충분한가요, HTTP/3까지 가야 하나요?
유선·저손실 환경 위주의 서비스라면 HTTP/2만으로도 체감 개선의 대부분을 얻습니다. HTTP/3의 이점(스트림별 손실 복구, 0-RTT, 연결 마이그레이션)은 모바일 사용자 비중이 높거나 해외처럼 RTT가 큰 구간에서 두드러집니다. HTTP/3는 항상 HTTP/2와 병행 제공되므로 켜서 손해 볼 것은 없습니다.
HTTP/2는 반드시 HTTPS여야 하나요?
스펙상 평문 HTTP/2(h2c)도 존재하지만 Chrome, Firefox, Safari 등 주요 브라우저는 모두 TLS 위에서만 HTTP/2를 협상합니다. 사실상 웹 서비스에서는 HTTPS가 전제 조건이라고 보면 됩니다. HTTP/3는 QUIC 자체에 TLS 1.3이 내장되어 있어 암호화 없는 모드가 아예 없습니다.
HTTP/3를 켰는데 브라우저가 계속 h2로 접속합니다. 왜죠?
가장 흔한 원인은 방화벽에서 UDP 443이 막혀 있는 경우입니다. 다음으로 Alt-Svc 헤더가 응답에 없거나, 첫 방문이라 아직 h2로 접속한 상태일 수 있습니다(브라우저는 Alt-Svc를 본 뒤에야 h3로 전환). 헤더 존재 여부와 UDP 443 오픈 상태를 순서대로 점검하세요.
HTTP/2로 바꾸면 기존 도메인 샤딩은 어떻게 처리해야 하나요?
정적 자원 도메인을 하나로 합치는 것이 원칙입니다. 당장 합치기 어렵다면 샤드 도메인들이 같은 인증서와 같은 IP를 쓰도록 구성하세요. 이 경우 브라우저가 HTTP/2 연결 병합(connection coalescing)으로 하나의 연결을 재사용해 샤딩의 부작용이 줄어듭니다.
서버 푸시(Server Push)는 써야 하나요?
아니요. HTTP/2 서버 푸시는 캐시 중복 전송 문제로 실효성이 낮아 Chrome이 2022년 지원을 제거했고 nginx도 기능을 내렸습니다. 렌더링에 필요한 자원을 미리 알리고 싶다면 Link 헤더의 preload나 103 Early Hints를 사용하는 것이 현재 권장 방식입니다.
내 사이트가 어떤 HTTP 버전을 쓰는지 코드는 어떻게 확인하나요?
브라우저 개발자도구 네트워크 탭에서 Protocol 열을 켜면 요청별로 h2, h3 표기를 볼 수 있습니다. 명령줄에서는 curl --http3 또는 curl -I --http2로 시험할 수 있고, 서버 접근 없이 확인하려면 OneWebDesk의 HTTP/2·HTTP/3 지원 확인 도구에 도메인만 입력하면 됩니다.

이 가이드와 함께 쓰면 좋은 도구

관련 가이드