우리가 매일 사용하는 웹(Web)은 멈춰있지 않습니다. 브라우저 주소창에 URL을 입력하고 엔터를 누르는 그 찰나의 순간, 데이터를 조금이라도 더 빠르고 효율적으로 전송하기 위해 프로토콜은 끊임없이 진화해 왔습니다. 1991년 팀 버너스 리가 고안한 단순한 텍스트 전송 규약이 어떻게 오늘날의 초고속 UDP 통신으로 발전했는지, 그 치열했던 진화과정을 정리해보겠습니다.
1. 태초의 웹, 단순함 그 자체였던 HTTP/0.9
이야기는 1991년 팀 버너스 리의 연구실에서 시작됩니다. 당시의 HTTP는 그야말로 '생존'을 위한 최소한의 기능만 갖추고 있었습니다. 복잡한 인사말이나 부가 정보는 사치였죠.
클라이언트가 서버에게 말을 거는 방식은 너무나 단순했습니다.
(Request)
GET /index.html
보시다시피 버전 정보도, 헤더도 없습니다. 오직 "이 파일 줘"라는 한 마디뿐입니다. 서버의 대답도 쿨하기 그지없었습니다.
(Response)
<html>
<body>
Hello World! This is a simple text page.
</body>
</html>
성공했다는 상태 코드(200 OK)조차 없이, 오직 본문 내용만 툭 던져주었습니다. 텍스트 위주의 초기 웹에서는 이 정도면 충분했지만, 웹이 성장하기엔 너무나 부족한 소통 방식이었습니다.
2. HTTP/1.0, 웹이 격식을 갖추기 시작하다
1996년, 웹은 더 이상 텍스트 쪼가리만 주고받는 곳이 아니게 되었습니다. 이미지를 보내야 했고, 브라우저의 종류를 알려야 했습니다. 그래서 HTTP/1.0부터는 헤더(Header)라는 명함을 교환하기 시작했습니다.
(Request)
GET /my-image.gif HTTP/1.0
User-Agent: NCSA_Mosaic/2.0
(Response)
HTTP/1.0 200 OK
Content-Type: image/gif
Content-Length: 1348
(binary image data...)
이제 요청 끝에 HTTP/1.0이라는 버전이 붙었고, User-Agent로 자신이 누구인지 밝힙니다. 응답 역시 200 OK라며 성공 여부를 명확히 하고, Content-Type을 통해 "이건 텍스트가 아니라 이미지야"라고 친절하게 알려주게 되었죠.
하지만 치명적인 문제가 있었습니다. 이미지 하나를 받을 때마다 매번 연결을 끊고 다시 맺어야 했습니다.
위 처럼 파일을 10개 받으려면 전화도 10번 걸어야 하는 비효율적인 상황이었습니다.
3. HTTP/1.1, 효율성을 위해 연결을 유지하다 (Keep-Alive)
이 문제를 해결하기 위해 1997년 등장한 HTTP/1.1은 Keep-Alive라는 개념을 도입합니다. 한 번 연결하면 끊지 않고 계속 대화하자는 약속입니다.
(Request)
GET /index.html HTTP/1.1
Host: http://www.example.com
Connection: keep-alive
(Response)
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 3050
여기서 가장 중요한 건 Connection: keep-alive입니다. "전화 끊지 말고 잠깐 기다려, 다음 파일도 달라고 할 거니까"라는 의미죠. 또한 Host 헤더가 필수가 되면서 하나의 IP로 여러 도메인을 운영하는 가상 호스팅도 가능해졌습니다.
하지만 여전히 한계는 존재했습니다. 바로 HOL(Head-of-Line) Blocking, 즉 '앞차 막힘 현상'입니다.
연결은 하나인데 순서대로 처리해야 하다 보니, 앞의 무거운 이미지 하나 때문에 뒤에 있는 가벼운 파일들이 하염없이 기다려야만 했습니다.
[요청 1: 대용량 이미지] -> (전송 중... 3초 소요)
[요청 2: 텍스트 파일] -> (이미지 다 받을 때까지 대기...)
[요청 3: 스타일 시트] -> (앞에 두 개 다 끝날 때까지 대기...)
4. HTTP/2, 도로를 쪼개서 동시에 달리다 (Multiplexing)
2015년, 이 '줄 서기' 문제를 해결하기 위해 HTTP/2가 등장했습니다. 핵심은 멀티플렉싱(Multiplexing)입니다. 하나의 연결 안에 여러 개의 '가상 차선(Stream)'을 만들어 동시에 데이터를 쪼개서 보냅니다.
HTTP/2는 사람이 읽는 텍스트가 아닌, 이진 프레임(Binary Frame)으로 데이터를 주고받습니다. 이를 개념적으로 표현하면 다음과 같습니다.
(Stream 1) HEADERS: method=GET, path=/image.jpg
(Stream 3) HEADERS: method=GET, path=/style.css
(Stream 3) DATA: body { color: red; } <-- 가벼운 CSS가 먼저 도착!
(Stream 1) DATA: (image part 1)
(Stream 1) DATA: (image part 2)
보시는 것처럼 요청은 순서대로 했지만, 응답은 파일 크기나 상황에 따라 뒤섞여서(Interleaving) 도착합니다. 더 이상 앞의 큰 파일 때문에 뒤의 작은 파일이 기다릴 필요가 없어진 것입니다.
하지만 완벽해 보이는 HTTP/2에도 아킬레스건은 있었습니다. 바로 기반이 되는 TCP 프로토콜입니다. 고속도로(HTTP/2)를 아무리 넓혀놔도, 도로 자체(TCP)가 유실되면(패킷 손실) 모든 차선이 멈춰버리는 문제는 여전했습니다.(TCP의 신뢰성있는 전송을 보장하기 위함.)
4. HTTP/3, TCP를 버리고 UDP로 혁신하다 (QUIC)
그래서 등장한 것이 최신 기술인 HTTP/3입니다. HTTP/3는 과감한 결단을 내립니다. 인터넷의 역사와 함께해 온 신뢰의 상징, TCP를 버리기로 한 것입니다. 대신 빠르지만 신뢰성이 낮다고 평가받던 UDP를 선택했고, 그 위에 구글이 개발한 QUIC이라는 새로운 프로토콜을 얹었습니다.
QUIC은 TCP가 하던 신뢰성 보장 기능을 애플리케이션 영역으로 가져와 재설계했습니다. 가장 큰 특징은 독립적인 스트림입니다. 이제는 패킷 하나가 손실되어도 해당 데이터만 잠시 멈출 뿐, 다른 데이터들은 아무 영향 없이 쌩쌩 달릴 수 있습니다. 진정한 의미의 병렬 처리가 가능해진 것입니다.
게다가 모바일 환경에서의 혁신도 이루어냈습니다. 예전에는 와이파이에서 LTE로 바뀌면 IP가 달라져 연결이 끊겼지만, QUIC은 고유한 ID로 연결을 식별하기 때문에 네트워크가 바뀌어도 끊김 없이 통신을 이어갑니다. 유튜브나 넷플릭스 같은 스트리밍 서비스가 이동 중에도 매끄러운 이유 중 하나가 바로 이 기술 덕분입니다.
마치며: 전송 계층을 넘나드는 진화
HTTP의 역사를 되짚어보면, 이는 단순한 기능 추가의 역사가 아닙니다. 병목 현상을 해결하기 위해 처음에는 헤더를 고치고(1.0/1.1), 그다음엔 메시지 구조를 바꾸고(2.0), 마침내 전송 계층 자체를 교체(3.0)하는 근본적인 재설계의 과정이었습니다.
지금도 웹 서버와 브라우저는 상황에 따라 HTTP/1.1, 2, 3을 오가며 최적의 방식으로 대화하고 있습니다. 단순한 텍스트 전송에서 시작해 전송 계층의 한계까지 뛰어넘은 HTTP. 그 끊임없는 진화 덕분에 우리는 오늘도 쾌적한 웹 서핑을 즐기고 있습니다.
'CS > Network' 카테고리의 다른 글
| [IT 용어] 페이로드(Payload)란? (0) | 2026.01.11 |
|---|---|
| 면접에 나오는 라우팅 프로토콜과 라우티드 프로토콜 (0) | 2025.12.22 |
| SNMP 프로토콜 (2) | 2025.12.20 |
| 모놀리식 아키텍쳐(MA)와 마이크로 서비스 아키텍쳐(MSA) (1) | 2024.09.26 |
| 가상화와 컨테이너 (1) | 2024.09.23 |