대부분의 개발자가 신경 쓰지 않는 전송 계층이 API의 모든 HTTP 요청을 처리합니다. 지난 25년 동안 이 역할은 TCP가 맡았습니다. 이후 Google은 TCP의 발전을 기다리는 대신 UDP 위에 QUIC을 구축했고, IETF는 이를 표준화했습니다. HTTP/3는 QUIC 위에서 동작하는 HTTP 버전입니다.
배관처럼 보이지만, 이 변화는 API 연결 속도, 불안정한 모바일 네트워크에서의 안정성, 병렬 요청의 연결 공유 방식에 영향을 줍니다. API를 설계하거나 운영한다면 무엇이 바뀌었고 무엇이 그대로인지, 현재 엔드포인트가 어떤 프로토콜을 사용하는지 확인할 수 있어야 합니다.
HTTP/1.1, HTTP/2, HTTP/3에서 요청, 응답, 상태 코드, JSON 페이로드는 동일합니다. Apidog처럼 API 계층에서 테스트하고 디버깅하는 도구는 전송 버전과 관계없이 그대로 사용할 수 있습니다. HTTP/2가 무엇이며 HTTP/2 API를 테스트하는 방법을 읽었다면, 이 글은 그다음 단계입니다.
QUIC 프로토콜이란?
QUIC은 RFC 9000에서 표준화된 전송 프로토콜입니다. TCP 대신 UDP 위에서 실행되며, 신뢰성·순서 지정·혼잡 제어를 사용자 공간에서 스트림별로 구현합니다. 첫 패킷부터 암호화도 내장됩니다.
핵심 설계는 네 가지입니다.
- UDP 기반: TCP는 운영체제 커널과 인터넷 미들박스에 구현되어 있어 변경이 어렵습니다. QUIC은 얇은 UDP 위에 자체 신뢰성 계층을 제공하므로, OS 업그레이드 대신 라이브러리 업데이트로 개선할 수 있습니다.
- 통합된 TLS 1.3: TCP와 TLS를 각각 핸드셰이크하는 대신 전송 핸드셰이크에 TLS 1.3을 통합합니다. 새 보안 연결을 한 번의 왕복으로 설정하며, 암호화되지 않은 QUIC은 없습니다.
- 독립 스트림: 연결 하나가 여러 스트림을 전달하고, 각 스트림이 독립적으로 처리됩니다. 손실된 패킷은 해당 스트림만 지연시킵니다.
- 연결 마이그레이션: TCP는 IP 주소와 포트가 바뀌면 연결이 끊깁니다. QUIC은 연결 ID를 사용하므로 Wi-Fi에서 5G로 전환해도 동일한 논리 연결을 유지할 수 있습니다.
RFC 9114에 정의된 HTTP/3는 HTTP 의미론을 QUIC 스트림에 매핑합니다. 메서드, 헤더, 상태 코드는 그대로이고 와이어 포맷과 전송 방식만 다릅니다.
HTTP/3와 HTTP/2의 실제 차이
HTTP/2는 여러 요청이 하나의 TCP 연결을 공유하도록 멀티플렉싱을 도입했습니다. 하지만 TCP는 하나의 바이트 스트림을 순서대로 전달합니다. 패킷 하나가 손실되면 재전송될 때까지 이후의 모든 바이트가 대기하며, 관련 없는 HTTP/2 스트림도 함께 멈춥니다. 이것이 전송 계층의 Head-of-Line(HOL) Blocking입니다.
따라서 손실이 많은 네트워크에서는 HTTP/2가 여러 연결을 사용하는 HTTP/1.1보다 느려질 수도 있습니다.
HTTP/3는 요청마다 고유한 QUIC 스트림을 사용합니다. 스트림 5의 패킷이 손실되어도 스트림 6부터 24까지는 계속 전송됩니다. 멀티플렉싱이 의도한 대로 스트림별로 독립 동작하는 것입니다.
| 항목 | TCP + TLS 1.3 기반 HTTP/2 | QUIC 기반 HTTP/3 |
|---|---|---|
| 새 연결 설정 | 2회 왕복(TCP + TLS) | 1회 왕복 |
| 재개된 연결 | 1회 왕복 | 0회 왕복(0-RTT) |
| 패킷 손실 영향 | 모든 스트림 차단 | 해당 스트림만 차단 |
| 네트워크 전환 | 연결 끊김 후 재연결 | 연결 마이그레이션 |
| 암호화 | 별도 계층, 이론상 선택 가능 | TLS 1.3 통합, 필수 |
0-RTT 주의사항
이전에 연결했던 서버에 재접속할 때 QUIC은 핸드셰이크가 끝나기 전에 애플리케이션 데이터를 보낼 수 있습니다. 지연 시간을 줄이는 데 유용하지만, 0-RTT 데이터는 공격자가 캡처해 재전송할 수 있습니다.
따라서 서버는 0-RTT에서 멱등성 요청만 허용해야 합니다. GET 재전송은 일반적으로 안전하지만, 결제를 처리하는 POST 재전송은 위험합니다. 엣지에서 0-RTT를 활성화한다면 멱등성이 없는 API 호출을 제외하거나 CDN의 처리 정책을 확인하세요.
HTTP/3가 API에 미치는 영향
연결 설정 비용 감소
RTT가 60ms인 모바일 클라이언트는 첫 API 요청 전에 TCP와 TLS 설정으로 약 120ms를 소비할 수 있습니다. HTTP/3는 이를 약 60ms로 줄이고, 재개된 연결에서는 거의 0ms까지 줄일 수 있습니다.
콜드 스타트, 백그라운드 복귀, 짧은 세션처럼 새 연결을 자주 만드는 모바일 앱에서 효과가 큽니다. 반대로 웜 연결 풀을 유지하는 서버 간 통합에서는 핸드셰이크 비용이 이미 상각되어 차이가 작습니다.
모바일 네트워크 전환 시 연결 유지
사용자가 Wi-Fi에서 요청을 시작한 뒤 5G로 이동한다고 가정해 보겠습니다.
- TCP: 진행 중인 요청이 실패하고 전체 재연결 및 재시도가 필요합니다.
- QUIC: 연결이 새 네트워크로 이동하므로 논리적 연결을 계속 유지합니다.
그 결과 클라이언트 로그의 타임아웃과 불완전한 쓰기를 줄일 수 있습니다.
패킷 손실 환경에서 병렬 요청 안정성 향상
대시보드가 15개 위젯을 병렬로 갱신하거나 동기화 엔진이 여러 업데이트를 동시에 전송하는 경우 HOL Blocking 제거가 특히 중요합니다.
깨끗한 네트워크에서는 HTTP/2와 HTTP/3의 성능 차이가 작습니다. 하지만 혼잡한 회의실 Wi-Fi나 지하철 셀룰러처럼 1~2%의 패킷 손실이 발생하면 HTTP/2는 여러 요청을 동시에 지연시키는 반면, HTTP/3는 요청을 독립적으로 진행합니다.
gRPC는 아직 대부분 HTTP/2 기반
gRPC는 HTTP/2 프레이밍과 트레일러에 의존하도록 설계되었습니다. gRPC 생태계는 아직 HTTP/3 매핑을 표준화하지 않았고, Go·Java·Python·Node의 주류 구현도 HTTP/3를 제공하지 않습니다.
.NET의 Kestrel은 실험적 기능으로 HTTP/3 기반 gRPC를 제공할 수 있지만 예외적인 사례입니다. gRPC와 HTTP/2를 사용하는 내부 API 아키텍처라면 당장 HTTP/3 마이그레이션을 계획할 필요는 없습니다.
스트리밍 및 실시간 트래픽
Server-Sent Events는 장기 HTTP 응답이므로 HTTP/3에서도 변경 없이 동작합니다.
WebSockets는 다릅니다. WebSocket 업그레이드는 TCP용으로 설계되었고, HTTP/3에 해당하는 RFC 9220과 WebTransport API는 아직 지원이 제한적입니다. WebSockets와 일반 HTTP 중 무엇을 선택할지 고민하고 있다면, 현재는 HTTP/3 지원 여부를 결정의 핵심 기준으로 삼지 않는 편이 좋습니다.
HTTP/3가 해결하지 못하는 문제
대부분의 API 지연 시간 문제는 전송 프로토콜이 아니라 애플리케이션에 있습니다.
인덱스가 없는 데이터베이스 쿼리로 엔드포인트가 400ms 걸린다면 HTTP/3는 느린 응답을 조금 더 빨리 전달할 뿐입니다. 캐싱, 페이로드 설계, N+1 쿼리, 연결 재사용이 실제 성능을 더 크게 좌우합니다. 전송 계층보다 먼저 구조화된 API 성능 테스트를 수행하세요.
HTTP/3의 효과가 큰 조건은 다음과 같습니다.
- 지연 시간이 긴 네트워크
- 패킷 손실이 많은 네트워크
- 세션 중 네트워크를 전환하는 모바일 클라이언트
- 짧은 연결을 많이 사용하는 클라이언트
안정적인 네트워크에서 동일 지역의 서버가 사용하는 일반적인 JSON API라면 차이는 벤치마크에서는 측정되지만 사용자에게는 거의 보이지 않을 수 있습니다.
운영 시에는 다음 사항도 고려하세요.
- 일부 기업 네트워크는 UDP 443을 차단할 수 있습니다. 클라이언트는 일반적으로 HTTP/2로 자동 폴백합니다.
- QUIC은 사용자 공간 암호화를 사용하므로, 튜닝된 커널 TCP보다 연결당 서버 CPU 사용량이 많을 수 있습니다.
현재 지원 현황
HTTP/3 채택률은 많은 백엔드 개발자의 예상보다 높습니다.
- 브라우저: Chrome, Edge, Firefox, Safari가 모두 기본적으로 HTTP/3를 지원합니다.
- CDN 및 엣지: Cloudflare, Fastly, Akamai, CloudFront가 지원합니다. Cloudflare에서는 토글로 활성화할 수 있습니다. 일반적인 배포 방식은 엣지에서 HTTP/3를 종료하고 오리진까지는 HTTP/1.1 또는 HTTP/2를 사용하는 것입니다.
-
서버: Nginx 1.25는
listen 443 quic;지시어로 실험적인 HTTP/3를 제공합니다. Caddy는 기본 활성화하고, LiteSpeed와 HAProxy도 지원합니다. Apache httpd는 지원하지 않습니다. - 런타임: Node.js는 안정적인 내장 HTTP/3 서버 지원이 없습니다. 이 역시 엣지 터미네이션이 널리 사용되는 이유입니다.
-
curl: HTTP/3 지원 TLS 스택으로 빌드된 경우
--http3플래그를 사용할 수 있습니다. 빌드별 지원 여부는 curl HTTP/3 문서에서 확인하세요.
API가 HTTP/3를 제공하는지 확인하기
서버는 Alt-Svc 응답 헤더로 HTTP/3를 광고합니다.
alt-svc: h3=":443"; ma=86400
이는 “앞으로 24시간 동안 UDP 443을 통해 HTTP/3를 사용할 수 있다”는 의미입니다.
curl -sI https://www.cloudflare.com | grep -i alt-svc
# alt-svc: h3=":443"; ma=86400
HTTP/3로 직접 요청하려면 HTTP/3가 활성화된 curl 빌드가 필요합니다.
curl --http3 -I https://cloudflare-quic.com
# HTTP/3 200
응답 상태 라인이 HTTP/2가 아니라 HTTP/3인지 확인하세요.
Chrome 개발자 도구에서는 다음 순서로 확인할 수 있습니다.
- Network 탭을 엽니다.
- 열 헤더를 마우스 오른쪽 버튼으로 클릭합니다.
- Protocol 열을 활성화합니다.
- API 요청 옆에서
h3를 찾습니다.
프로덕션에서는 협상된 프로토콜을 액세스 로그에 기록하세요. h2와 h3 트래픽 비율을 보면 실제로 얼마나 많은 클라이언트가 HTTP/3의 이점을 얻는지 알 수 있습니다.
전송 계층과 함께 API 동작도 검증해야 합니다. 동일한 엔드포인트에 Apidog를 사용해 상태 코드, 응답 스키마, 지연 시간 예산을 확인하세요. 계약이 깨져 있다면 전송 계층의 성능 향상은 의미가 없습니다.
엣지에서 HTTP/3를 활성화하기 전후에 Apidog를 무료로 다운로드하고 동일한 테스트 스위트를 실행해 보세요. 특히 모바일 네트워크에서 실제 응답 시간이 어떻게 달라지는지 확인할 수 있습니다.
자주 묻는 질문
HTTP/3는 HTTP/2보다 빠른가요?
깨끗하고 지연 시간이 짧은 네트워크에서는 차이가 거의 없습니다. 지연 시간이 길거나 패킷 손실이 많은 환경에서는 더 빠를 수 있습니다. 핸드셰이크 왕복을 줄이고, 패킷 하나의 손실이 모든 멀티플렉스 요청을 지연시키지 않기 때문입니다.
도입 전에는 자신의 트래픽 프로파일로 측정하세요. HTTP/2 연결 오류가 발생한다면 프로토콜보다 SSLV3_ALERT_HANDSHAKE_FAILURE 문제 같은 TLS 계층 문제일 가능성이 큽니다.
HTTP/3는 TCP를 사용하나요?
아니요. HTTP/3는 QUIC 위에서 실행되고, QUIC은 일반적으로 UDP 443을 사용합니다. QUIC은 TCP의 신뢰성·순서 지정·혼잡 제어를 사용자 공간에서 스트림별로 구현합니다.
UDP 443이 차단되면 클라이언트는 보통 TCP 기반 HTTP/2로 자동 폴백합니다.
HTTP/3를 위해 API 코드를 변경해야 하나요?
대부분 필요하지 않습니다. 메서드, 헤더, 상태 코드, 본문 등 HTTP 의미론은 동일합니다. 변경 작업은 주로 CDN, 로드 밸런서, 서버 설정에 해당합니다.
다만 0-RTT 초기 데이터가 멱등성 요청으로 제한되는지 반드시 확인하세요.
HTTP/3에서 gRPC를 사용할 수 있나요?
현재는 대부분 어렵습니다. gRPC 와이어 포맷이 HTTP/2에 묶여 있고, 주류 gRPC 라이브러리는 HTTP/3 전송을 제공하지 않습니다. .NET은 실험적 지원을 제공합니다.
gRPC 서비스는 HTTP/2에 유지하고, HTTP/3가 먼저 효과를 낼 수 있는 공용·브라우저 대면·모바일 대면 REST 엔드포인트부터 도입하는 전략이 현실적입니다.
Top comments (0)