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/3 | B의 필요한 바이트가 갖춰졌다면 A의 복구를 기다리지 않고 B를 전달할 수 있습니다. A 안의 순서는 여전히 복구해야 합니다. |
UDP를 사용한다고 해서 QUIC이 신뢰성을 포기하는 것은 아닙니다.
QUIC은 UDP 위에 자체적인 전송 계층을 구축합니다.
패킷 유실 탐지, 재전송, 흐름 제어, 혼잡 제어를 QUIC이 직접 수행하고, 애플리케이션 데이터는 여러 스트림에 나뉘어 전달됩니다.
단, 혼잡 제어는 연결 전체에 걸쳐 동작하고, 하나의 QUIC 패킷에 여러 스트림 데이터가 함께 들어 있으면 그 스트림들이 같이 영향을 받을 수 있습니다.
연결 수립 속도
QUIC은 전송 핸드셰이크와 TLS 1.3 핸드셰이크를 통합합니다.
손실이나 추가 Retry가 없는 일반적인 최초 연결에서는 클라이언트가 약 1 RTT 뒤 보안 애플리케이션 데이터를 보낼 수 있습니다. 재개 정보와 서버의 수락 조건이 맞으면 핸드셰이크 완료 전 0-RTT 데이터를 먼저 보낼 수 있지만, 이것이 전체 핸드셰이크가 끝났다는 뜻은 아닙니다.
0-RTT는 재전송 공격(replay)에 노출될 수 있습니다. 단순히 GET이나 멱등 요청이라는 이유만으로 안전을 단정하지 말고, 애플리케이션의 중복 처리·재생 방지 정책과 서버의 수락 여부를 함께 판단해야 합니다.
예시: 80 ms RTT에서 먼저 보낸다는 의미 손실·Retry·처리 시간이 없고 원문의 일반 최초 연결 조건이 맞으면, 클라이언트의 보안 애플리케이션 데이터 전송 가능 시점을 약 1×80=80 ms로 모델링합니다. 재개가 수락되는 0-RTT 요청은 첫 전송에 함께 실을 수 있지만 서버까지의 전파 시간과 응답을 기다리는 시간이 없어지는 것은 아닙니다. 또 서버가 early data를 거절하면 그 데이터를 다시 처리할 전송이 필요합니다. 이 숫자는 위 조건의 계산이며 curl이나 QUIC 구현의 실행 결과가 아닙니다.
재개 요청을 독립 판단하기 중복 적립을 막는 장치가 없는 포인트 적립 요청을 0-RTT로 보내려 합니다. 네트워크가 빠르고 재개 정보가 있다는 사실만으로 적절한 선택일까요?
전송 가능성과 업무 결과를 나누는 풀이
아닙니다. 재생된 요청을 다시 처리하면 포인트가 두 번 적립될 수 있습니다. 서버의 early data 수락 정책과 업무의 중복 식별·처리 정책을 먼저 정하고, 안전하게 재처리할 수 없는 요청은 핸드셰이크 뒤 보내는 선택을 검토합니다. 빠른 최초 전송은 적립을 정확히 한 번만 수행한다는 보장이 아닙니다.
연결 마이그레이션
모바일 환경에서 Wi-Fi와 LTE를 전환하면 IP 주소가 바뀝니다.
TCP 연결은 보통 4튜플(출발지 IP/포트, 목적지 IP/포트)에 강하게 묶여 있어 경로가 바뀌면 연결이 끊기기 쉽습니다.
QUIC은 Connection ID로 연결을 식별하고, 새 네트워크 경로를 검증한 뒤 같은 연결 상태를 이어갈 수 있도록 설계되어 있습니다.
연결 이동 시 Connection ID를 바꿔 사용할 수 있으므로 같은 숫자를 계속 유지해야 하는 것은 아닙니다. 실제 성공 여부는 이동 허용 설정, 서버와 로드 밸런서의 연결 상태 처리, 경로 검증, NAT·방화벽의 UDP 허용에 달려 있습니다.
주소가 바뀌어도, 새 경로 검증을 거쳐 연결을 이어갈 수 있습니다
핸드셰이크가 확인되고 이동이 허용된 연결입니다. 같은 경로에서 돌아온 동일한 값을 대조합니다. 각 단계의 값과 전환 이유를 비교합니다.
HTTP/3 · 연결 이동
주소가 바뀌어도, 새 경로 검증을 거쳐 연결을 이어갈 수 있습니다
QUIC은 IP·포트만으로 연결을 구분하지 않습니다. Connection ID로 기존 연결을 찾고 새 경로를 검증하지만, 서버·로드 밸런서·UDP 경로의 지원 조건도 필요합니다.
화살표는 한 성공 사례의 메시지 방향이고 위에서 아래로 순서를 읽습니다. 기존 Wi-Fi 경로는 생략했습니다. 마지막 문장은 서버의 값 대조이며 새로운 메시지가 아닙니다. 경로 검증 전의 전송·증폭 제한과 경로 MTU는 별도 조건입니다.
기존 경로 · Wi-Fi
현재 주소와 포트로 QUIC 데이터를 주고받습니다.
유지할 상태: 같은 연결의 스트림·암호화 상태입니다.
새 경로 · 이동통신망
IP 주소나 포트가 달라집니다. Connection ID로 서버의 기존 연결 상태를 찾을 수 있습니다.
구분: 이동 때 사용할 Connection ID는 바뀔 수도 있습니다.
경로 검증 · 이어서 전송
새 주소에 실제로 도달할 수 있는지 검증하고, 조건이 맞으면 같은 연결을 새 경로에서 이어갑니다.
조건: 이동 허용 설정, 연결 상태 라우팅, NAT·방화벽의 UDP 허용을 확인합니다.
개념 순서이며 모든 패킷 교환이나 즉시·무손실 전환을 보장하지 않습니다. Connection ID는 사용자 신원 인증 수단이 아니고, 재연결을 완료한 다른 연결과도 구분합니다.
이 예의 조건
- 본문과 전체 도표의 예를 따라 새 주소부터 응답 검증까지 진행합니다.
관계도의 보충 설명
| 구분 | 전체 도표의 내용 |
|---|---|
| 관계 설명 | 핸드셰이크 confirmed·이동 허용·새 Connection ID 사용 가능을 가정한 성공 경로입니다. 새 주소의 클라이언트가 패킷을 보내고 서버가 새 주소로 PATH_CHALLENGE, 클라이언트가 같은 값의 PATH_RESPONSE를 보냅니다. 서버의 값 대조는 challenge를 보낸 경로를 검증하며 사용자 로그인은 별개입니다. 검증 전 데이터 전송의 전면 금지나 무손실 전환을 뜻하지 않습니다. |
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 새 주소 핸드셰이크가 확인되고 이동이 허용된 연결입니다. |
|
|
| 연결 찾기 서버가 CID로 기존 연결 상태를 찾습니다. |
|
|
| 경로 challenge 서버가 새 경로로 8바이트 challenge를 보냅니다. |
|
|
| 응답 검증 같은 경로에서 돌아온 동일한 값을 대조합니다. |
|
|
주소가 바뀌어도, 새 경로 검증을 거쳐 연결을 이어갈 수 있습니다
핸드셰이크가 확인되고 이동이 허용된 연결입니다. 같은 경로에서 돌아온 동일한 값을 대조합니다. 각 단계의 값과 전환 이유를 비교합니다.
HTTP/3 · 연결 이동
주소가 바뀌어도, 새 경로 검증을 거쳐 연결을 이어갈 수 있습니다
QUIC은 IP·포트만으로 연결을 구분하지 않습니다. Connection ID로 기존 연결을 찾고 새 경로를 검증하지만, 서버·로드 밸런서·UDP 경로의 지원 조건도 필요합니다.
화살표는 한 성공 사례의 메시지 방향이고 위에서 아래로 순서를 읽습니다. 기존 Wi-Fi 경로는 생략했습니다. 마지막 문장은 서버의 값 대조이며 새로운 메시지가 아닙니다. 경로 검증 전의 전송·증폭 제한과 경로 MTU는 별도 조건입니다.
기존 경로 · Wi-Fi
현재 주소와 포트로 QUIC 데이터를 주고받습니다.
유지할 상태: 같은 연결의 스트림·암호화 상태입니다.
새 경로 · 이동통신망
IP 주소나 포트가 달라집니다. Connection ID로 서버의 기존 연결 상태를 찾을 수 있습니다.
구분: 이동 때 사용할 Connection ID는 바뀔 수도 있습니다.
경로 검증 · 이어서 전송
새 주소에 실제로 도달할 수 있는지 검증하고, 조건이 맞으면 같은 연결을 새 경로에서 이어갑니다.
조건: 이동 허용 설정, 연결 상태 라우팅, NAT·방화벽의 UDP 허용을 확인합니다.
개념 순서이며 모든 패킷 교환이나 즉시·무손실 전환을 보장하지 않습니다. Connection ID는 사용자 신원 인증 수단이 아니고, 재연결을 완료한 다른 연결과도 구분합니다.
이 예의 조건
- 본문과 전체 도표의 예를 따라 새 주소부터 응답 검증까지 진행합니다.
관계도의 보충 설명
| 구분 | 전체 도표의 내용 |
|---|---|
| 관계 설명 | 핸드셰이크 confirmed·이동 허용·새 Connection ID 사용 가능을 가정한 성공 경로입니다. 새 주소의 클라이언트가 패킷을 보내고 서버가 새 주소로 PATH_CHALLENGE, 클라이언트가 같은 값의 PATH_RESPONSE를 보냅니다. 서버의 값 대조는 challenge를 보낸 경로를 검증하며 사용자 로그인은 별개입니다. 검증 전 데이터 전송의 전면 금지나 무손실 전환을 뜻하지 않습니다. |
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 새 주소 핸드셰이크가 확인되고 이동이 허용된 연결입니다. |
|
|
| 연결 찾기 서버가 CID로 기존 연결 상태를 찾습니다. |
|
|
| 경로 challenge 서버가 새 경로로 8바이트 challenge를 보냅니다. |
|
|
| 응답 검증 같은 경로에서 돌아온 동일한 값을 대조합니다. |
|
|
예시: 새 주소가 실제로 받는지 확인하기 핸드셰이크가 confirmed 상태이고 능동 이동이 허용되며, 서버 주소는 그대로이고 새 Connection ID도 사용할 수 있다고 가정합니다. 클라이언트가 이동통신망의 새 주소에서 보낸 패킷을 서버가 기존 연결로 찾습니다. 서버는 새 주소로 예측하기 어려운 8 B 값을 PATH_CHALLENGE에 보내고, 클라이언트는 받은 값 그대로 PATH_RESPONSE에 돌려보냅니다. 같은 값을 받은 서버는 그 challenge를 보낸 경로의 도달 가능성을 확인합니다. RFC 9000의 경로 검증 규칙은 수신자의 같은 경로 응답 의무와 검증 시작자의 값 대조를 구분합니다.
그림은 성공한 한 교환을 발췌합니다. 경로 검증이 끝나야 모든 데이터 전송을 처음 시작한다는 뜻은 아닙니다. 검증 전 전송에는 증폭 제한 등의 조건이 있고, 경로 MTU 확인도 따로 필요할 수 있습니다.
새 경로 실패를 독립 판단하기 PATH_CHALLENGE의 응답이 끝내 도착하지 않았지만 이전 Wi-Fi 경로는 여전히 검증돼 사용할 수 있습니다. 반드시 새 연결을 만들거나 기존 연결을 즉시 종료해야 하나요?
경로와 연결을 나누는 풀이
새 경로가 실패한 것과 연결 전체가 실패한 것은 다릅니다. 유효한 이전 경로를 계속 사용하는 선택이 가능합니다. 사용할 수 있는 다른 경로도 없어졌는지는 별도로 판단합니다. Connection ID만 안다고 새 주소의 도달 가능성이 확인되는 것도 아니며, 사용자 로그인은 이 검증의 대상이 아닙니다.
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·처리량·지연의 실측 차이로 결정합니다. |
# 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=86400curl --http3는 HTTP/2·HTTP/1.1로도 연결을 시도하므로 명령 성공만으로 HTTP/3 사용을 증명하지 못합니다. 실제 응답 버전을 확인해야 하며, HTTP/3만 시험하려면 --http3-only를 사용합니다. 위 head -3은 진단 출력을 자를 수 있고, Alt-Svc는 광고일 뿐 이 요청이 QUIC으로 연결됐다는 증거가 아닙니다.
문제가 생기면 협상된 HTTP 버전, UDP 차단, QUIC 연결·스트림 오류를 분리해 기록합니다. 패킷 캡처만으로 읽을 수 없는 내부 손실·복구 상태는 구현이 제공하는 qlog와 서버 로그를 함께 확인합니다.
다음 절에서는 HTTP의 요청-응답 모델을 벗어나 양방향 실시간 통신을 가능하게 하는 WebSocket을 다루겠습니다.