내 HTTP는 모두 한 단계 진화한다.


HTTP의 역사를 살펴보자.
HTTP/1.0 출시 이후 HTTP/1.1부터 최신 HTTP/3까지 어떤 문제를 해결하기 위해 어떻게 진화해 왔는지!!
HTTP/1.1 - 첫 번째 최적화와 새로운 숙제
초창기 HTTP/1.0은 요청 하나당 TCP 연결을 하나씩 맺고 끊는 매우 비효율적인 방식이었다.
이를 개선하고자 HTTP/1.1은 keep-alive라는 개념을 도입했다.
keep-alive : 한번 맺은 TCP 연결을 일정 시간 동안 유지하며 여러 요청을 처리하는 방식
→ 이를 통해 불필요한 TCP 연결/해제 과정을 줄여 '연결 오버헤드'라는 병목을 해결했다. (연결/해제 과정에서의 비용이 크다.)
하지만 이로 인해 새로운 숙제가 생겼다. 바로 HOL Blocking(Head-of-Line Blocking)
새로운 병목 현상 HOL Blockin은 뭐야~?
keep-alive 연결은 한번에 하나만 가능하다. 먼저 요청한 이미지 파일이 커서 다운로드가 느려지면 그 뒤에 있는 작은 CSS, JS 파일 요청들은 하염없이 기다려야만 한다. 즉 한 요청이 완료되어야 다른 요청을 처리하므로 대기 시간이 길어진다.
그래서 과거 프론트엔드 개발자들은 수십 개의 JS/CSS 파일을 웹팩 같은 도구로 하나의 파일로 묶는 작업에 집착했다고...
HTTP/2 : 같이 좀 삽시다.
HTTP/2는 HTTP/1.1의 HOL Blocking이라는 문제점을 해결하기 위해 등장했다. 핵심 해결책은 바로 멀티플렉싱!!
Multiplexing : 하나의 TCP 연결 위에 여러 요청과 응답이 동시에 오고 갈 수 있는 여러 개의 가상 차선(Stream)을 만드는 기술
-> 큰 이미지 파일이 다운로드되는 동안에도 다른 CSS, JS 파일들도 스트림을 통해 다운로드가 가능하져 HTTP 레벨의 HOL Blocking이 해결!!
그럼 이게 비동기에요??
멀티플렉싱과 비동기는 서로 다른 계층 개념이다.
비동기 = 프로그래밍 모델
애플리케이션 레벨에서 '하나의 작업이 끝날 때까지 기다리지 않고 다음 작업을 바로 시작'하는 방식
멀티플렉싱 = 네트워크 전송 기술
'하나의 통신 연결 위에서 여러 데이터를 섞어서 보내는' 방식
가상 차선이란건 정확히 뭔가요? 연결을 여러개 하는건가?
Stream의 정체
가상 차선(Stream)은 '가상의 연결'이 아니라 하나의 실제 TCP 연결 내에서 논리적으로 구분된 양방향 데이터 흐름
실제 연결은 단 하나!!
HTTP/2는 서버와 통신을 시작할 때 TCP 3-Way Handshake를 한 번만 수행하여 하나의 TCP 연결을 만든다.
논리적인 흐름
하나의 연결 안에 여러 개의 독립적인 데이터 흐름(Stream)을 만드는 것. 각 Stream은 고유한 ID를 가진다
예를 들어 index.html은 Stream 1번으로, style.css는 Stream 3번으로, script.js는 Stream 5번으로..
프레임 단위 전송
각 Stream의 데이터는 프레임이라는 아주 작은 단위로 쪼개진다. 각 프레임에는 자신의 Stream ID 가 붙어있다
재조립
이 프레임들이 뒤섞여서 하나의 TCP 연결을 통해 전송되면 수신 측에서는 각 프레임의 Stream ID를 보고 다시 원래의 Stream으로 재조립한다.
즉 새로운 TCP 연결을 내는 것이 아니라 하나의 TCP 연결 위에 여러 개의 Stream을 그려놓은 것
하지만 이번에도 또 다른 문제가 발생했다. 바로 TCP 연결 자체가 막히는 문제였다.
새로운 병목현상 : TCP의 HOL Blocking
HTTP/2가 아무리 여러 개의 Stream을 만들어도 그 모든 Stream은 결국 하나의 TCP 연결 위에 있다. TCP는 데이터의 순서를 보장하기 때문에 중간에 TCP 패킷 하나가 유실되면 그 뒤의 모든 패킷(모든 Stream의 데이터)이 재전송될 때까지 멈춰야했다.
HTTP/3 : QUIC on UDP
HTTP/2도 해결하지 못한 TCP의 근본적인 한계를 극복하기 위해 HTTP/3는 매우 과감한 선택을 한다. TCP를 버리고 UDP 위에 QUIC이라는 새로운 프로토콜을 쌓아 올린 것!!
- 해결책 - QUIC
QUIC은 신뢰성이 없는 UDP 위에서 TCP의 신뢰성(패킷 재전송, 순서 보장 등)을 직접 구현한 프로토콜- TCP HOL Blocking 해결 : QUIC은 각 Stream을 독립적인 것으로 간주한다. 따라서 한 Stream에서 패킷 유실이 발생하더라도 다른 Stream은 전혀 영향을 받지 않고 계속 데이터를 전송할 수 있다.
- 연결 시간 단축 : TCP와 TLS Handshake 과정을 통합하여 첫 연결에 걸리는 시간을 크게 단축했다.
[실습] 내 눈으로 확인하는 HTTP


이론은 알았으니 실습을 해보자!! node.js를 활용하여 http 버전을 바꿔가며 서버를 실행하고 실습을 진행했다. (지피티야 고마워~)
각 테스트는 40개의 요청을 보내는 테스트이며 개발자 도구에서 프로토콜을 확인한 결과이다.
기대 결과?!
HTTP/1.1
총 완료 시간이 더 길게 나온다. 동시에 6개 정도만 처리되고, 뒤 요청이 앞 요청에 줄 세워져 대기(HOL)하는 패턴이 Waterfall에 나타납니다.
HTTP/2
동일 리소스/지연인데도 총 완료 시간이 확연히 짧음. 워터폴 막대들이 넓게 겹치며 동시에 진행(멀티플렉싱)되는 모습.
HTTP/1.1

초록색: Waiting (TTFB - Time To First Byte)
- 브라우저가 서버로 요청을 보낸 후 서버로부터 첫 번째 응답 데이터 조각이 도착할 때까지 걸린 대기 시간
- 이 시간이 길다면 네트워크 문제보다는 서버 자체의 처리 속도가 느리다는 신호일 가능성이 높다. (복잡한 데이터베이스 조회, 오래 걸리는 API 로직 수행 등)
파란색: Content Download
- 서버로부터 응답이 오기 시작한 후 모든 데이터를 전부 다운로드하는 데 걸린 전송 시간
- 이 시간이 길다면 이는 서버의 처리 속도보다는 리소스의 크기가 너무 크거나(e.g., 고화질 이미지, 대용량 동영상) 사용자 네트워크 속도가 느리다는 것을 의미

- 프로토콜이 모두 http/1.1로 표시
- 차트를 보면 요청들이 6개씩 그룹지어 순차적으로 실행되는 계단 현상이 발생
- 40개의 리소스를 모두 받는데 약 8초가 넘는 시간 소요
해석
HTTP/1.1의 한계를 볼 수 있다.
계단 현상이 발생하는 이유 : 두 가지 병목 현상이 동시에 작용하기 때문
- 브라우저의 연결 개수 제한 : 대부분의 브라우저는 하나의 도메인에 동시에 맺을 수 있는 TCP 연결 개수를 6개로 제한한다. 따라서 7번째 요청은 앞선 6개의 요청 중 하나가 끝나야만 시작할 수 있다.
- HOL Blocking : 하나의 연결 내에서도 요청은 순서대로 처리되어야 한다.
→ 따라서 한 번에 6개씩만 요청을 처리하고 다음 그룹이 대기하는 현상이 발생!!
HTTP/2


- 프로토콜 열에 모두 http/2로 표시
- 차트를 보면 HTTP/1.1과 달리 모든 요청이 거의 동시에 시작된다. 계단 현상 X
- 총 소요 시간은 약 1.8초 = HTTP/1.1에 비해 4배 이상 빠름
해석
이것이 바로 HTTP/2 멀티플렉싱
HTTP/2는 하나의 TCP 연결을 맺고 그 위에 스트림이라는 논리적인 통로를 만들어 모든 요청을 동시에 병렬로 처리
6개 연결 제한이 사라졌기 때문에 40개의 요청이 모두 지체 없이 시작 가능하다.
결론
HTTP/1.1의 연결 제한과 HOL Blocking이 실제 웹 성능에 얼마나 큰 영향을 미치는지 그리고 HTTP/2의 멀티플렉싱이 이 문제를 얼마나 효과적으로 해결하는지를 확인하였다.
요약
- 총 완료 시간
- h1 ≈ 9.5초,
- h2 ≈ 2.4초 → 대략 4배 더 빠름
- 워터폴 패턴
- h1: 묶음(≈6개) 단위 진행 + 뒤 요청은 대기(Queue/Stall/TTFB 증가) → HOL 영향 뚜렷
- h2: 한 번에 광범위 동시 진행(막대가 넓게 겹침) → 멀티플렉싱 효과

오늘의 Q&A
Q1. QUIC은 신뢰성이 없는 UDP 위에서 TCP의 신뢰성(패킷 재전송, 순서 보장 등)을 직접 구현한 프로토콜이라고 했는데 그럼 TCP와 융합한건가요? 즉, TCP를 사용했다는 말인가요? HTTP/3는 UDP를 사용했다고 했는데 명확한 의미가 궁금합니다.
A1. QUIC은 TCP를 사용하지 않는다.
우선 TCP에 대해 알고가자!!
TCP는 신뢰성을 보장하기 위해 패킷 재전송, 순서 보장, 흐름 제어 등의 기능들을 제공한다. 중요한 포인트는 이러한 기능들이 운영체제(OS) 커널 수준에 구현되어 있다는 것이다.
UDP는 알다시피 일단 보내는 기능에 집중하며 신뢰정이 없다. 순서 보장, 패킷 유실 확인을 지원하지 앟는다. TCP의 신뢰성을 UDP 위에서 구현했다는 말은 TCP가 커널 수준에서 제공하던 순서 보장, 패킷 유실과 확인과 같은 신뢰성을 보장하는 기능들을 애플리케이션 계층에서 직접 다시 만들어서 사용한다는 의미이다.
비유하자면
UDP는 가장 저렴하고 빠른 일반 우편 서비스(도착 보장 안 됨)
TCP는 등기, 배송 추적, 분실 시 재발송 등 모든 기능이 포함된 국가 운영 우체국 시스템
QUIC은 일반 우편 서비스(UDP)를 이용하지만, 자체적으로 모든 소포에 바코드를 붙이고, GPS 추적기를 달고, 분실 시 바로 다시 보내주는 특송 회사
따라서 HTTP/3의 기반 프로토콜인 QUIC이 UDP를 사용하여 데이터를 실어 나른다는 의미이다.
-> 신뢰성 보장의 책임은 이제 TCP(OS)가 아닌 QUIC(애플리케이션)이 진다.
Q2. HTTP/3는 TCP와 TLS Handshake 과정을 통합하여 첫 연결에 걸리는 시간을 크게 단축했다고 하셨는데 이 부분도 TCP를 사용했다는 뜻인가요? 정확히 어떤 원리와 과정으로 연결 시간이 단축되는 것인가요?
A2. 역시 TCP를 사용했다는 뜻이 아니다.
TCP 핸드셰이크와 TLS 핸드셰이크가 하던 역할을 하나로 통합했다는 의미!!
전통적인 TCP 기반의 HTTPS
TCP 3-Way Handshake로 연결하고 TLS Handshake로 암호화한다. 그 과정에서 여러번의 연결이 이루어지기 때문에 오래걸린다.
QUIC 기반의 HTTP/3
QUIC은 이 두 과정을 한 번에 처리한다.
첫 연결 : 클라이언트가 서버에 보내는 첫 패킷에 연결 요청 정보(TCP의 역할)와 암호화 정보(TLS의 역할)를 모두 담아서 보낸다. 서버 역시 응답 패킷에 연결 수락 정보와 암호화 정보를 함께 담아 보낸다.
-> 단 한 번의 왕복으로 연결 설정과 암호화가 동시에 완료
재연결 : 한 번 연결했던 서버에 다시 접속할 때는 이전에 사용했던 암호화 키를 이용해 첫 패킷부터 바로 실제 데이터(HTTP 요청)를 담아 보낼 수 있다. 왕복(Handshake)이 필요 없다.
이것이 HTTP/3가 연결 시간을 획기적으로 단축할 수 있는 원리!!
Q3. HTTP/1.1의 경우 브라우저에서 대부분 6개의 TCP 연결이 이루어진다고 하셨는데 6개로 고정인건가요? 만약 요청이 2000개가 오더라도 TCP 연결은 6개만 사용하나요?
A3. 6개로 고정!! 브라우저마다 차이는 있지만 그래봐야 5~8개 사이를 유지한다. 2000개의 요청이 와도 똑같다.
'CS 먹고 레벨업~' 카테고리의 다른 글
| JOIN이 느린건 내 골반이 멈추지 않는 탓일까? ㅜ.ㅜ (2) | 2025.10.28 |
|---|---|
| 이건 트랜잭션 두번째 레슨 좋은 건 너만 알기 (0) | 2025.10.21 |
| 자OO스가 모르는 것, 못하는 것, 내가 전부 가르쳐줄게. (0) | 2025.10.15 |
| 서버 하나 추가해봐 (0) | 2025.09.24 |
| 혼자야? (1) | 2025.09.17 |