HTTP/3는 어떻게 헤드오브라인 블로킹을 없애는가: QUIC 스트림 독립성의 원리

🤖 AI Summary
HTTP/2는 하나의 TCP 연결에 여러 요청을 병렬로 실어 보내지만, 그 병렬성이 TCP에는 보이지 않아 패킷 하나가 손실되면 모든 트랜잭션이 멈추는 헤드오브라인 블로킹을 겪어요. RFC 9114의 표현으로는 손실되거나 순서가 뒤바뀐 패킷 하나가 직접 영향을 받지 않은 트랜잭션까지 전부 stall시키죠. HTTP/3는 이 문제를 QUIC로 넘어가 해결합니다. QUIC 스트림은 서로 독립적이라 한 스트림이 막히거나 손실을 겪어도 다른 스트림의 진행을 막지 않고, 각 요청-응답 쌍은 하나의 QUIC 스트림을 씁니다. QUIC은 UDP 위에서 동작하며, 암호와 전송 핸드셰이크를 하나로 합쳐 연결 설정 지연을 줄이고, 커넥션 ID로 네트워크 경로가 바뀌어도 연결을 유지해요. 근거는 모두 RFC 9114와 RFC 9000 원문입니다.
블로그 목차
헤드오브라인 블로킹이란 무엇인가
줄을 서서 기다리는데 맨 앞 사람이 멈추면 뒤가 전부 멈추는 상황, 그것이 헤드오브라인 블로킹(Head-of-Line Blocking, 이하 HOL 블로킹)입니다. 네트워크에서는 앞선 데이터 조각 하나가 도착하지 못하면 그 뒤에 온 조각들이 이미 도착했더라도 처리되지 못하고 대기하는 현상을 말하죠. 이 글은 HTTP/2가 왜 이 문제를 완전히 벗어나지 못했는지, HTTP/3가 QUIC로 넘어가면서 어떻게 없앴는지를 RFC 원문 기준으로 정리합니다.
먼저 배경 하나만 짚겠습니다. HTTP/2는 하나의 TCP 연결 위에 여러 요청을 스트림으로 나눠 병렬로 실어 보냅니다. 앞선 HTTP/1.1이 요청을 사실상 하나씩 처리하던 것에 비하면 큰 진전이었어요. 문제는 그 병렬성이 어느 계층에서 보이느냐입니다.
HTTP/2가 이 문제를 못 벗어난 이유
핵심은 스트림이 HTTP 계층의 개념이지 TCP 계층의 개념이 아니라는 데 있습니다. RFC 9114는 이렇게 설명해요. "HTTP/2 멀티플렉싱의 병렬적 성격이 TCP의 손실 복구 메커니즘에는 보이지 않기 때문에, 손실되거나 순서가 뒤바뀐 패킷 하나가 그 패킷의 직접적 영향을 받았는지와 무관하게 모든 활성 트랜잭션을 지연(stall)시킨다"는 것입니다.
풀어 말하면 이렇습니다. TCP는 자기가 나르는 바이트 흐름을 하나의 순서 있는 스트림으로만 봅니다. 그 안에 HTTP 스트림이 여러 개 섞여 있다는 사실을 모르죠. 그래서 중간 패킷 하나가 빠지면 TCP는 그 자리를 메울 때까지 뒤따라온 모든 바이트를 위로 올려보내지 않습니다. HTTP/2가 애써 요청을 병렬로 나눠도, 전송 계층에서 한 번 막히면 그 위의 모든 스트림이 함께 멈추는 것이죠. HTTP/2는 애플리케이션 계층의 HOL 블로킹은 풀었지만, 전송 계층의 HOL 블로킹은 TCP를 쓰는 한 남아 있었습니다.

QUIC의 답: 스트림이 서로 독립적이다
HTTP/3는 TCP를 버리고 QUIC이라는 새 전송 위에서 동작합니다. QUIC의 핵심 설계가 바로 스트림 독립성이에요. RFC 9114는 "스트림들은 서로 독립적이므로, 어떤 한 스트림이 차단되거나 패킷 손실을 겪더라도 다른 스트림들의 진행을 막지 않는다"고 규정합니다. 앞의 HTTP/2 문장과 정확히 반대죠.
이것이 가능한 이유는 QUIC이 스트림을 전송 계층에서부터 알고 있기 때문입니다. RFC 9000은 "QUIC은 서로 다른 스트림에 실린 바이트들 사이의 순서를 보장하는 어떠한 수단도 제공하지 않는다"고 명시해요. 언뜻 단점처럼 들리지만 정반대입니다. 스트림 간 순서를 강제하지 않으니, 한 스트림에서 패킷이 빠져도 다른 스트림은 자기 순서만 맞으면 그대로 진행할 수 있습니다. TCP가 모든 것을 한 줄로 세워 하나가 막히면 전부 멈췄던 것과 달리, QUIC은 줄을 여러 개로 나눠 둔 셈이죠.
HTTP/3의 매핑과 QUIC이 얹히는 자리
HTTP/3가 QUIC 스트림을 쓰는 방식은 단순합니다. RFC 9114는 "각 요청-응답 쌍은 하나의 QUIC 스트림을 소비한다"고 정의해요. 요청 하나와 그에 대한 응답 하나가 독립된 스트림 하나를 차지하니, 한 요청의 패킷이 늦어도 다른 요청의 응답은 먼저 도착해 처리될 수 있습니다.
그리고 QUIC 자체는 어디에 얹힐까요. RFC 9000 기준 QUIC 패킷은 UDP 데이터그램에 실려 전달됩니다. 기존 시스템과 네트워크에 배포하기 쉽게 하기 위해서예요. 정리하면 계층이 이렇게 바뀝니다. HTTP/2는 HTTP가 TCP 위에 얹혔고, HTTP/3는 HTTP가 QUIC 위에, QUIC이 다시 UDP 위에 얹힙니다. 순서 보장과 손실 복구를 TCP에서 QUIC으로 옮겨 오면서, 스트림 단위로 다룰 수 있게 된 것이 차이의 뿌리죠. CDN 엣지처럼 손실·지연이 잦은 마지막 구간을 다루는 계층에서 이 스트림 독립성은 특히 의미가 커요.
덤으로 따라오는 것: 연결 설정 지연과 경로 변경
QUIC이 주는 이점은 HOL 블로킹 제거만이 아닙니다. RFC 9000은 "QUIC은 암호 핸드셰이크와 전송 핸드셰이크를 결합해 연결 설정 지연을 최소화한다"고 밝혀요. 기존에는 TCP 핸드셰이크와 TLS 핸드셰이크를 순차로 거쳐야 했는데, QUIC은 이 둘을 합쳐 연결을 여는 왕복 횟수를 줄이죠. 다만 이 문장은 연결 설정 지연을 줄인다는 사실까지를 말하며, 0-RTT 같은 세부 동작의 수치를 단정하지는 않으니 그 부분은 별도 확인이 필요합니다.
다른 하나는 커넥션 마이그레이션이에요. RFC 9000은 "커넥션 마이그레이션은 커넥션 식별자를 사용해 연결이 새로운 네트워크 경로로 이전될 수 있도록 한다"고 설명합니다. TCP 연결은 출발지와 도착지의 IP·포트 네 값으로 묶여, 와이파이에서 셀룰러로 바뀌면 연결이 끊겼습니다. QUIC은 연결을 IP가 아니라 커넥션 ID로 식별하므로, 네트워크가 바뀌어도 같은 연결을 이어 갈 수 있어요. 이동 중 끊김이 잦은 모바일 환경에서 체감이 큰 부분입니다. HTTP/2 자체의 상태를 점검하려면 HTTP/2 자가진단 글을, 이런 프로토콜 개선이 사용자 경험 지표로 어떻게 이어지는지는 Core Web Vitals 자가진단 글에서 이어 보실 수 있습니다.
이것만 기억하세요
HTTP/2는 TCP 위에서 패킷 하나가 손실되면 모든 스트림이 멈추는 전송 계층 헤드오브라인 블로킹을 겪습니다(RFC 9114). HTTP/3는 QUIC으로 넘어가 스트림을 서로 독립적으로 만들어, 손실된 스트림만 멈추고 나머지는 진행하게 했어요. 각 요청-응답은 QUIC 스트림 하나를 쓰고, QUIC은 UDP 위에서 동작합니다. 덤으로 핸드셰이크 결합으로 연결 설정 지연을 줄이고, 커넥션 ID로 네트워크 경로가 바뀌어도 연결을 유지합니다.
자주 묻는 질문 (FAQ)
Q. 헤드오브라인 블로킹이 정확히 무엇인가요?
앞선 데이터 하나가 도착하지 못하면 뒤에 이미 도착한 데이터까지 대기하게 되는 현상입니다. HTTP/2는 하나의 TCP 연결에 여러 스트림을 실어 보내는데, TCP가 스트림을 구분하지 못해 패킷 하나가 손실되면 RFC 9114 표현대로 모든 활성 트랜잭션이 함께 멈춥니다. 이것이 전송 계층의 헤드오브라인 블로킹입니다.
Q. HTTP/2도 멀티플렉싱이 되는데 왜 이 문제가 남았나요?
HTTP/2의 멀티플렉싱은 HTTP 계층의 개념이라 TCP에는 보이지 않기 때문입니다. TCP는 자기가 나르는 바이트를 하나의 순서 있는 흐름으로만 취급하므로, 그 안에 여러 스트림이 있어도 중간 패킷이 빠지면 뒤따르는 모든 바이트를 막습니다. HTTP/2는 애플리케이션 계층의 블로킹은 해결했지만 전송 계층 블로킹은 TCP를 쓰는 한 남았습니다.
Q. QUIC은 어떻게 이 문제를 없앴나요?
QUIC 스트림을 서로 독립적으로 설계했기 때문입니다. RFC 9114는 한 스트림이 차단되거나 패킷 손실을 겪어도 다른 스트림의 진행을 막지 않는다고 규정하고, RFC 9000은 QUIC이 서로 다른 스트림 간 바이트 순서를 보장하지 않는다고 명시합니다. 스트림 간 순서를 강제하지 않으니, 한 스트림의 손실이 다른 스트림을 멈추지 않습니다.
Q. HTTP/3는 TCP를 안 쓰나요?
쓰지 않습니다. HTTP/3는 QUIC 위에서 동작하고, QUIC 패킷은 UDP 데이터그램에 실려 전달됩니다. 순서 보장과 손실 복구를 TCP 대신 QUIC이 담당하되, 스트림 단위로 처리한다는 점이 핵심 차이입니다. 각 요청-응답 쌍은 하나의 QUIC 스트림을 사용합니다.
Q. 스트림 독립성 말고 다른 이점도 있나요?
있습니다. QUIC은 암호 핸드셰이크와 전송 핸드셰이크를 결합해 연결 설정 지연을 최소화합니다(RFC 9000). 또 커넥션 마이그레이션으로, 연결을 IP가 아니라 커넥션 식별자로 구분하므로 와이파이에서 셀룰러로 네트워크 경로가 바뀌어도 연결이 유지됩니다. 모바일 환경에서 체감이 큰 부분입니다.



