안동민 개발노트

본문 시작

HTTP/3와 QUIC

HTTP/3가 QUIC의 독립 스트림·통합 TLS·빠른 연결·연결 이동으로 TCP의 구조적 지연을 줄이는 방식을 이해합니다.

이전 절에서 HTTP/2가 HTTP 계층의 HOL Blocking을 크게 줄였지만, TCP 계층의 HOL Blocking은 여전히 남아있다는 것을 확인했습니다.

HTTP/3는 HTTP의 의미를 QUIC 위에 매핑해 이 문제를 줄입니다.


TCP의 구조적 한계

TCP는 순서 보장을 핵심 특성으로 설계되었습니다.

앞쪽 바이트 구간이 유실되면, 그 뒤의 바이트가 도착했어도 빈 구간을 복구할 때까지 애플리케이션 전달이 지연됩니다. TCP는 패킷 번호가 아니라 바이트 순서를 복구합니다.


QUIC의 해결 방식

QUIC은 UDP 위에서 동작하는 안전한 범용 전송 프로토콜입니다.

초기에는 Google의 실험적 프로토콜에서 출발했지만, 표준 QUIC에서는 QUIC을 약어가 아니라 프로토콜 이름으로 정의합니다.

전송 방식스트림 A의 바이트가 빠졌을 때
HTTP/2같은 TCP 바이트 열에서 뒤에 있는 스트림 B의 데이터도 전달이 지연될 수 있습니다.
HTTP/3B의 필요한 바이트가 갖춰졌다면 A의 복구를 기다리지 않고 B를 전달할 수 있습니다. A 안의 순서는 여전히 복구해야 합니다.

UDP를 사용한다고 해서 QUIC이 신뢰성을 포기하는 것은 아닙니다.

QUIC은 UDP 위에 자체적인 전송 계층을 구축합니다.

패킷 유실 탐지, 재전송, 흐름 제어, 혼잡 제어를 QUIC이 직접 수행하고, 애플리케이션 데이터는 여러 스트림에 나뉘어 전달됩니다.

단, 혼잡 제어는 연결 전체에 걸쳐 동작하고, 하나의 QUIC 패킷에 여러 스트림 데이터가 함께 들어 있으면 그 스트림들이 같이 영향을 받을 수 있습니다.


연결 수립 속도

QUIC은 전송 핸드셰이크와 TLS 1.3 핸드셰이크를 통합합니다.

손실이나 추가 Retry가 없는 일반적인 최초 연결에서는 클라이언트가 약 1 RTT 뒤 보안 애플리케이션 데이터를 보낼 수 있습니다. 재개 정보와 서버의 수락 조건이 맞으면 핸드셰이크 완료 전 0-RTT 데이터를 먼저 보낼 수 있지만, 이것이 전체 핸드셰이크가 끝났다는 뜻은 아닙니다.

0-RTT는 재전송 공격(replay)에 노출될 수 있습니다. 단순히 GET이나 멱등 요청이라는 이유만으로 안전을 단정하지 말고, 애플리케이션의 중복 처리·재생 방지 정책과 서버의 수락 여부를 함께 판단해야 합니다.


연결 마이그레이션

모바일 환경에서 Wi-Fi와 LTE를 전환하면 IP 주소가 바뀝니다.

TCP 연결은 보통 4튜플(출발지 IP/포트, 목적지 IP/포트)에 강하게 묶여 있어 경로가 바뀌면 연결이 끊기기 쉽습니다.

QUIC은 Connection ID로 연결을 식별하고, 새 네트워크 경로를 검증한 뒤 같은 연결 상태를 이어갈 수 있도록 설계되어 있습니다.

연결 이동 시 Connection ID를 바꿔 사용할 수 있으므로 같은 숫자를 계속 유지해야 하는 것은 아닙니다. 실제 성공 여부는 이동 허용 설정, 서버와 로드 밸런서의 연결 상태 처리, 경로 검증, NAT·방화벽의 UDP 허용에 달려 있습니다.


QUIC의 암호화 범위

TCP 자체는 암호화를 제공하지 않고, 보통 TLS가 그 위에 올라갑니다.

QUIC은 TLS 1.3 핸드셰이크를 전송 프로토콜 안에 통합하고, 가능한 많은 패킷 필드를 암호화와 무결성 보호 대상으로 삼습니다.

애플리케이션 데이터는 암호화되지만 모든 헤더가 숨겨지는 것은 아닙니다. RFC 9001의 Initial 패킷 보호 키는 공개 정보로 유도할 수 있어 기밀성을 보장하지 않습니다. Version Negotiation·Retry도 애플리케이션 데이터와 같은 보호 범위로 해석하면 안 됩니다.


HTTP/3 도입 현황과 판단 기준

HTTP/3는 이미 주요 브라우저, CDN, 대형 서비스에서 널리 지원되지만, 실제 사용 비율은 네트워크와 서비스 유형에 따라 차이가 큽니다.

예를 들어 Cloudflare의 2025 Year in Review는 Cloudflare 네트워크 요청 기준으로 HTTP/2가 50%, HTTP/1.x가 29%, HTTP/3가 21%였다고 보고했습니다.

이는 웹 전체의 절대 비율이라기보다 측정 지점에 따른 관측값으로 봐야 합니다.

상황검토할 조건
모바일·고지연·고손실HTTP/3의 경로 이동과 스트림 독립성이 이점이 될 수 있는지 같은 조건에서 비교합니다.
CDN 사용엣지 지원 외에도 클라이언트와 경로의 UDP 443 허용, 실제 협상 결과를 확인합니다.
UDP 차단·이전 클라이언트HTTP/2 등 사용 가능한 전송 경로를 유지하고 실패율을 따로 봅니다.
내부 서비스안정된 저지연망에서는 CPU·처리량·지연의 실측 차이로 결정합니다.
http3_check.sh
# HTTP/3 지원으로 빌드된 curl에서 확인
curl -I --http3 https://www.google.com 2>&1 | head -3
# 응답 예시(실행 결과 아님): HTTP/3 200

# Alt-Svc 헤더에서 HTTP/3 대체 서비스 광고 확인
curl -sI https://www.cloudflare.com | grep -i alt-svc
# 광고 예시(실행 결과 아님): alt-svc: h3=":443"; ma=86400

curl --http3는 HTTP/2·HTTP/1.1로도 연결을 시도하므로 명령 성공만으로 HTTP/3 사용을 증명하지 못합니다. 실제 응답 버전을 확인해야 하며, HTTP/3만 시험하려면 --http3-only를 사용합니다. 위 head -3은 진단 출력을 자를 수 있고, Alt-Svc는 광고일 뿐 이 요청이 QUIC으로 연결됐다는 증거가 아닙니다.

문제가 생기면 협상된 HTTP 버전, UDP 차단, QUIC 연결·스트림 오류를 분리해 기록합니다. 패킷 캡처만으로 읽을 수 없는 내부 손실·복구 상태는 구현이 제공하는 qlog와 서버 로그를 함께 확인합니다.

다음 절에서는 HTTP의 요청-응답 모델을 벗어나 양방향 실시간 통신을 가능하게 하는 WebSocket을 다루겠습니다.