Head-of-Line Blocking이란?
Head-of-Line Blocking(HOL Blocking)은 줄의 맨 앞(Head)에 있는 작업이 지연되면서 뒤에 있는 작업들까지 함께 대기하게 되는 현상을 말합니다. 편의점 계산대를 떠올려보면 이해가 쉽습니다. 한 줄로 서서 기다리는데 맨 앞사람이 카드 결제 오류로 시간을 오래 끌면, 뒤에 있는 사람들은 자기 물건을 다 계산할 준비가 되어 있어도 앞사람이 끝날 때까지 꼼짝없이 기다려야 합니다. 네트워크 통신에서도 이와 동일한 상황이 발생하는데, 하나의 연결(커넥션) 안에서 먼저 보낸 요청이나 패킷이 지연되면 그 뒤에 있는 데이터가 먼저 도착해도 처리되지 못하고 대기하게 됩니다.
HTTP/2에서 왜 여전히 발생할까?
HTTP/1.1은 하나의 TCP 연결에서 요청을 순차적으로만 처리할 수 있어 HOL Blocking이 심각했습니다. 이를 해결하기 위해 HTTP/2는 ‘스트림(Stream)’이라는 개념을 도입해 하나의 TCP 연결 위에서 여러 요청과 응답을 동시에 주고받는 멀티플렉싱(Multiplexing)을 지원합니다. 애플리케이션 레벨에서는 요청들이 서로를 기다리지 않아도 되도록 설계된 것입니다.
문제는 이 모든 스트림이 결국 하나의 TCP 연결을 공유한다는 점입니다. TCP는 데이터를 순서대로 전달해야 하는 프로토콜이기 때문에, 만약 특정 패킷 하나가 네트워크 상에서 유실되면 TCP는 그 패킷이 재전송되어 도착할 때까지 이후에 도착한 모든 패킷을 애플리케이션에 전달하지 않고 붙잡아 둡니다. 결국 HTTP/2에서 독립적으로 동작하던 여러 스트림의 데이터가 같은 TCP 연결 안에 섞여 있다 보니, 패킷 하나의 유실이 전체 스트림의 지연으로 이어지는 것입니다. 즉 애플리케이션 계층의 HOL Blocking은 해결했지만, 전송 계층인 TCP 레벨의 HOL Blocking은 여전히 남아있는 셈입니다.
실무에서 왜 중요한가
이 문제는 특히 무선 네트워크나 혼잡한 환경처럼 패킷 유실이 잦은 상황에서 두드러집니다. 이미지 여러 장을 동시에 요청했는데 그중 한 이미지의 패킷 하나가 유실되면, 이미 도착한 다른 이미지들의 데이터까지 전달이 지연되어 전체 페이지 로딩 속도가 눈에 띄게 느려질 수 있습니다.
이런 한계 때문에 등장한 것이 HTTP/3입니다. HTTP/3는 TCP 대신 UDP 기반의 ‘QUIC’ 프로토콜을 사용하는데, QUIC은 스트림별로 독립적인 전송 순서를 관리합니다. 한 스트림의 패킷이 유실되어도 다른 스트림은 영향을 받지 않고 계속 진행할 수 있어, 전송 계층의 HOL Blocking까지 근본적으로 해결합니다. 개발자 입장에서는 단순히 ‘연결이 빨라졌다’는 것을 넘어, 왜 특정 네트워크 환경에서 HTTP/2보다 HTTP/3의 체감 성능이 더 좋은지를 이해하는 핵심 배경 지식이 바로 이 HOL Blocking 개념입니다.