HTTP란?
HTTP는 웹 환경에서 정보를 주고받는 의사소통의 규칙이며 클라이언트와 서버간의 요청-응답 구조로 통신이 이루어진다.
데이터 전송에 TCP 프로토콜, 라우팅에 IP프로토콜을 사용하는 구조를 갖추고 있다.
HTTP 버전별 특징
HTTP/0.9 | HTTP/1.0 | HTTP/1.1 | |
메서드 | GET | HEAD, POST 추가 | PUT, PATCH, DELTE 등 추가 |
헤더 | 미존재 | http 버전 정보, 상태코드, Content-type 등 |
Connection, Host 등 |
응답 | HTML 문서만 | 다양한 문서 가능 | - |
HTTP 0.9
헤더가 존재하지 않고 GET 요청만 존재하며 http메시지가 한줄로 이루어진 원라인 프로토콜이었다.
HTTP 1.0
상태코드가 추가되어 오류 파악에 용이해지게 됬다. 1.0 이전에는 에러 페이지를 별도로 작성해야했다.
헤더영역이 추가되었고 Content-type을 통해 다양한 문서를 전송할수 있게 되었다.
1.0까지 커넥션 하나에 하나의 요청만 가능한 구조였기에 요청마다 tcp연결과 종료를 설정하는 오버헤드가 존재하였다.
HTTP 1.1
1.1의 가장 중요한 개념은 **연결 지속성(Persistent Connection)**이다.
Connection을 지정한 timeout 시간 동안 종료하지 않고 요청-응답을 반환하기 위해 유지할 수 있게 되었다.
즉, 하나의 커넥션에 여러 요청-응답을 반환할 수 있다.
// 연결 지속
Connection : Keep-Alive
Keep-Alive : timeout:5, max=1000
// 연결 지속X
Connection: Close
1.1에서는 **Piplelining 방식도 지원**하는데 요청을 한번에 보내고 응답을 이후에 받아 대기시간을 줄이는 것이다.
허나 응답의 순서는 요청 순서대로 받아야하기에 첫번째 요청의 응답이 늦어지게 되는 경우 다음 응답도 대기해야 하기에 Pipelinig을 쓰지 않는 방식과 비교하여 큰 이득이 없었다. 또한 Pipelining 구현의 복잡성, 서버의 Pipelinig 미지원 등의 문제로 대부분의 브라우저에서 Pipelining 방식을 비활성화하였다.
또다른 특징 중 하나는 Host 헤더의 추가이다. Host 헤더는 요청을 보낼 도메인 주소이다.
HTTP/1.0 이전에는 하나의 IP 주소에 하나의 도메인만 연결할 수 있었다.
HTTP/1.1에서 Host 헤더를 통해 가상 호스팅을 가능하게 했다. 가상 호스팅이란 하나의 서버가 여러 도메인을 소유하고 각 도메인에 연결된 서비스를 제공할 수 있는 것이다. 이를 통해 우리는 서버 1대에서 http 통신을 하는 여러 서비스를 제공할 수 있게 된 것이다.
http 버전별 [요청-응답] 처리 과정
HTTP/1.0 | HTTP/1.1 (Persistent Connection) |
HTTP/1.1 (PipeLining) |
![]() |
![]() |
![]() |
- 요청과 응답에 대해 매번 커넥션 연결과 종료를 해야함 |
- 일정 시간 내에 들어온 요청에 대해 커넥션 유지하여 사용 - 매 요청 커넥션을 연결하고 종료하지 않으므로 latency를 줄임 |
- '요청-응답'을 반복하지 않고 요청을 여러개 보내고 응답을 받을 수 있음 - But, 응답은 반드시 요청 순서대로 전송해야함. 이로인해 head of line blocking 발생 |
=> 결국 모든 요청-응답은 동기적으로 동작
Head Of Line Blocking
PipeLining 방식에서 요청 순서대로 응답되므로 특정 요청의 응답 처리시간이 길어진다면 다음 응답들도 모두 대기 후 전송된다.
1번 요청이 10초, 2번과 3번 요청이 1초만에 처리되어 응답을 보낼수 있어도 2, 3번 응답은 10초를 대기하고 응답을 전송하게 되고 이러한 현상을 Head of Line Blocking이라고 한다.
잠깐, http1.1에서도 결국 요청-응답 순서가 지켜지는데 어떻게 브라우저에 비동기 통신이 지원되지??
대부분의 브라우저에서 default로 사용하는 http 버전은 1.1이다.
그런데 최신 브라우저에서 비동기 통신이 지원되는 것을 잘 알고 있다.
HTTP 통신의 방식을 보면 응답은 결국 요청 순서대로 전달되는 규칙이 지켜지기에 동기적으로 동작한다.
어떻게 비동기적으로 동작하는 것일까??
"하나의 도메인에 여러 TCP 연결 활용"
브라우저는 도메인 하나에 여러개의 TCP 연결을 수립시켜준다.
대부분의 브라우저에 기본값으로 도메인당 6개의 TCP 연결이 설정되어있다.
커넥션 하나 내에서는 동기지만 커넥션을 여러개 사용하므로 비동기적으로 동작시킬 수 있는 것이다.
HTTP/2.0
멀티플레싱
멀티플렉싱이란 다중화 통신이라는 뜻으로 여러개의 저수준 채널을 하나의 고수준 채널로 통합하는 것을 말한다.
응용계층에 존재하는 하나의 커넥션에 여러개의 병렬스트림을 두어 전송 계층을 통해 데이터를 주고 받을 수 있는 것이다.
다수의 요청과 응답을 독립적으로 처리 가능하게 한 것이다.
Multiplexing
바이너리 프레임과 병렬스트림
HTTP 2.0에서 멀티플렉싱을 가능하게 만든 이유는 바이너리 프레임과 병렬스트림에 있다.
하나의 커넥션 안에 여러개의 병렬 스트림을 두고 각 요청과 응답을 별개의 스트림을 통해 전달한다.
응용계층에서는 HTTP 메시지를 여러개의 프레임으로 쪼갠 바이너리 프레임을 사용하며
바이너리 프레임은 Header , Data frame으로 구성되며 Stream ID를 식별자로 갖는다.
식별자인 Stream ID를 통해 어떤 스트림에서 전송됬는지 구분이 가능해졌다.
각 요청과 응답을 독립된 스트림으로 전달하더라도 stream ID를 통해 스트림을 분류하고 재조립할 수 있기에, 선행하는 요청-응답 처리로 후행 요청-응답의 처리가 지연되는 HOLB 문제를 해결할 수 있게 되었다.
허나, 우리가 주의해야할 것은 이 병렬 스트림은 응용계층에서 구현된 것이지,
실제 전송계층에서 사용되는 TCP에서는 여전히 직렬로 순서를 보장하는 방식으로 패킷이 전달된다.
멀티플렉싱을 통해 독립적으로 여러 요청을 처리하였다고 하지만 이는 응용계층에서만 해당되는 얘기이고,
실제 전송계층에서는 TCP 특성상 순서를 지키며 데이터가 전송되고 있다.
여전히 TCP 계층에서 패킷 유실과 같은 상황이 발생하면 그 다음 패킷 모두 영향을 받는 구조이다.
(전송계층에서 HOLB 해결 안됨)
이외 추가 기능
- 서버푸시
- 서버에서 클라이언트가 필요할 것 같은 정보를 미리 파악하여 전달 가능
(ex. html파일을 요청하면 서버에서 html파일에 사용되는 css, js파일을 함께 보냄
- 서버에서 클라이언트가 필요할 것 같은 정보를 미리 파악하여 전달 가능
- 헤더 압축(중복 제거)
이전 버전까지는 요청/응답마다 헤더 정보 또한 반복해서 전달해야 했지만 허프만 코드를 이용하는 HPACK 알고리즘을 이용하여 헤더를 압축하여 전송했고 이로 인해 패킷 사이즈 감소
HTTP 3 - QUIC 프로토콜
HTTP3는 TCP의 순서 보장을 위한 HOLB 문제를 전송계층에서 해결할 수 없는 구조적 문제를 탈피하고자 데이터 전송 프로토콜을 UDP로 변경하게 되었고, QUIC이라는 별도의 프로토콜에 신뢰성을 보장하는 구조를 갖추게 하였다.
먼저 UDP에 대해 간단히 알아보자
UDP의 패킷구조는 위와 같이 port만 존재할 정도로 매우 단순하다.(체크섬은 필수가 아님)
TCP 패킷처럼 신뢰성있는 전송을 위한 seq number, ack number, window size와 같은 값이 존재하지 않는다.
TCP 통신은 상대방이 응답을 받았는지 확인하는 구조이지만, UDP는 상대방이 응답을 받았는지 관심 없고 오직 자신이 보내는 것에 맞춰져 있다.
따라서 속도는 빠르지만 신뢰성이 떨어지는 구조이다.
QUIC에서는 어떻게 UDP 기반에서 신뢰성 있는 데이터 전송을 가능하게 했는지 알아보자.
QUIC 패킷 구조
Quic에서도 TCP 패킷 처럼 순서 번호와 ack, window 같은 값을 갖게 되었다.
ack과 window 값이 있으니 TCP처럼 흐름제어와 혼잡제어가 가능하다.
Packet No를 순서대로 조립하고 중간에 유실된 패킷이 존재하는지 에러 검출 또한 가능해졌다.
HOLB 문제 해결
UDP 프로토콜에서는 패킷의 전달 순서가 상관 없기에 HOLB 문제가 발생하지 않는다.
필요한건 각 요청과 응답을 받는 쪽에서 분류하여 재조립할 수 있어야한다.
Quic의 패킷에는 Stream ID가 포함되어 있고 이를 통해 재조립하여 각 요청-응답을 분리한다.
예를 들어 아래와 같이 패킷의 순서가 달라도 StreamID로 구별했을 때, Stream 단위로 순서대로 조립이 가능하다.
이와 같은 방식으로 전송계층에서 HOLB 문제를 해결할 수 있게 되는 것이다.
- Packet1 { streamID: 1, byte 0-499 }
- Packet3 { streamID: 1, byte 500-699 }
- Packet2 { streamID: 2, byte 0-499 }
이외 HTTP 3.0의 특징
[QUIC의 연결]
QUIC은 3 Way Handshake 과정을 거치지 않는다.
TCP는 연결시 기본적으로 1 RTT (Round Trip Time)가 필요하고, 여기에 TLS를 사용하면 TLS로 인한 RTT도 필요하다.
반면 QUIC은 첫 연결 설정에 1 RTT만 소요된다.
TLS 자체를 가지고 있기 때문에, 연결 설정에 필요한 정보와 함께 데이터도 보내버리기 때문이다.
그리고 한번 연결에 성공했다면 서버는 그 설정을 캐싱하여 캐싱 유효시간 동안 연결을 유지하기 때문에 0 RTT만에 통신을 시작할 수도 있다.
(캐싱정보 유효시간은 5분에서 24시간 까지 설정에 따라 매우 다양함)
[Connection ID]
Connection ID(CID)는 연결에 대한 고유한 식별자이다.
Connection ID를 사용하면 전송계층 이하의 네트워크 계층의 변경사항이 생겨도 연결에 영향을 받지 않는다.
중간에 IP가 변경되더라도 한번 수립된 Connection ID로 데이터가 연결되므로 데이터 전달을 끊기지 않고 지속할 수 있다.
이를 통해 ip 변경으로 새롭게 연결하는 상황을 방지할 수 있다.
'OS & Network > Network' 카테고리의 다른 글
TLS 연결 수립 과정 (0) | 2025.05.04 |
---|---|
DNS, GSLB, CDN (0) | 2025.05.02 |
OSI 7계층 (0) | 2025.05.01 |
TCP 깊게 이해하기 (0) | 2023.08.15 |