TCP 를 버리고 UDP 위의 QUIC 로 옮긴 HTTP.
HTTP/3 = HTTP over QUIC, QUIC 는 UDP 위에서 돈다
왜 UDP 인가
- TCP 는 커널과 중간 장비(NAT · 방화벽 · 미들박스)에 깊이 박혀 있다
- 새 기능을 넣어도 중간 장비가 이해 못 해 통과되지 않는다 (ossification)
- 바꾸는 것이 사실상 불가능하다
그래서 유저 공간에서 구현할 수 있는 UDP 위에 새로 쌓았다 애플리케이션 업데이트만으로 프로토콜을 개선할 수 있게 된 것이다
얻은 것
- 스트림별 독립
- 한 스트림의 손실이 다른 스트림을 막지 않는다 (TCP HoL 해소)
- 연결 수립과 TLS 를 합쳐 왕복이 줄었다 (1-RTT, 재개 시 0-RTT)
- 연결 ID 기반이라 IP 가 바뀌어도 연결이 유지된다 (연결 이주)
- 와이파이 ↔ LTE 전환에서 끊기지 않는다
- TLS 1.3 이 프로토콜에 내장돼 있다 (암호화가 선택이 아니다)
설정과 운영 체크포인트
server {
listen 443 ssl;
listen 443 quic reuseport;
http2 on;
http3 on;
add_header Alt-Svc 'h3=":443"; ma=86400';
}
□ 빌드에 QUIC 지원이 포함돼 있는가 nginx -V 로 확인 □ UDP 443 이 방화벽·보안그룹에 열려 있는가 ← 가장 흔한 누락 □ LB·CDN 이 UDP 를 통과시키는가 □ Alt-Svc 를 보내고 있는가
Alt-Svc 가 없으면 브라우저는 h3 가 있는지 모른다 첫 요청은 항상 TCP 로 온다 — h3 만으로는 시작할 수 없다
0-RTT 의 대가
재개 시 첫 요청을 왕복 없이 보낼 수 있다 그런데 그 데이터는 재전송 공격(replay)에 취약하다
-
공격자가 캡처한 0-RTT 데이터를 그대로 다시 보낼 수 있다
-
조회(GET)처럼 멱등한 요청에만 허용한다
-
결제 같은 상태 변경에는 쓰지 않는다
지금 어디까지 왔나
-
nginx — 1.25.0 부터 실험적 지원. 이후 CUBIC 혼잡 제어 · 0-RTT 등이 추가됐다
-
RFC 9114 — HTTP/3 표준
-
RFC 9220 — WebSocket over HTTP/3 — 2022 표준화됐으나 주요 구현이 아직 없다
-
'지원한다' 와 '쓸 수 있다' 는 다르다 — 버전과 함께 확인한다
CPU 비용이 다르다
QUIC 은 유저 공간에서 돌기 때문에 패킷 처리 비용이 TCP 보다 크다 커널의 TCP 스택은 오랜 최적화와 오프로드(TSO·GSO)를 받는다
- 트래픽이 매우 큰 서버에서는 CPU 사용이 눈에 띄게 오를 수 있다
- 켜기 전후로 CPU 를 반드시 비교한다
언제 켜는 것이 이득인가
이득이 큰 조건
- 모바일 비중이 높다 (손실률 · 네트워크 전환)
- 지리적으로 멀다 (왕복이 비싸다)
- 작은 요청이 많다 (핸드셰이크 비중이 크다)
이득이 작은 조건
- 데이터센터 내부 통신 (손실이 거의 없다)
- 대용량 파일 하나를 받는 워크로드
- CPU 가 이미 빡빡하다
"켜면 좋다" 가 아니라 "우리 트래픽에서 이득이 있나" 로 판단한다 켜기 전후 p99 와 CPU 를 같이 재는 것이 최소한이다
관측이 어려워진다
-
UDP 라서 기존 TCP 기반 도구(tcpdump 분석 · netstat 상태)가 덜 맞는다
-
페이로드가 전부 암호화돼 중간에서 볼 수 있는 것이 거의 없다
-
방화벽·미들박스가 UDP 를 다르게 취급한다
-
서버 쪽 로그와 지표에 더 의존하게 된다
-
$server_protocol 을 로그에 남겨 h2/h3 비율을 추적한다
면접 함정
- ❌ "UDP라서 신뢰성이 없다" → QUIC이 재전송·순서 보장을 스트림 단위로 직접 한다.
- ❌ "켜면 무조건 빨라진다" → 손실이 적은 환경에서는 차이가 작고 CPU는 더 든다.