Post

네트워크 - HTTP 기본 개요

1. HTTP 개요

HTTP는 웹의 애플리케이션 계층 프로토콜이다. 웹(월드와이드웹, www)은 1990년대 초 등장한 네트워크로 원할 때 데이터를 받을 수 있는 온디맨드 특성, 모든 사람이 낮은 비용으로 발행할 수 있는 장점 등으로 주류로 자리잡았다.

웹에서 클라이언트와 서버는 서로 HTTP 메세지를 교환하여 통신한다. HTTP 프로토콜은 이러한 메세지의 구조, 클라이언트와 서버가 메세지를 어떻게 교환하는지에 대해 정의한다.

웹 페이지

웹 페이지는 객체들로 구성되며 이러한 객체들은 단일 URL로 지정할 수 있는 하나의 파일(HTML, 이미지, Javascript 등)이다. 대부분 웹 페이지는 하나의 HTML 파일과 여러 참조 객체로 구성되며 HTML 파일은 참조 객체를 URL로 참조한다.


2. 요청 - 응답 모델

img.png

HTTP는 클라이언트가 HTTP 프로토콜에 맞게 데이터를 요청하면 서버가 이를 바탕으로 적절한 웹 페이지를 반환하는 방식으로 구성되어 있다. HTTP 프로토콜에서 데이터를 요청하는 과정은 웹 브라우저에 구현되어 있고 웹 브라우저는 받은 웹 페이지를 렌더링하는 역할도 수행한다. HTTP 프로토콜에서 요청을 받아 적절한 웹 페이지를 반환하는 과정은 웹 서버에 구현되어 있다.

HTTP/2까지는 TCP를 전송 프로토콜로 사용하여 브라우저와 서버 프로세스는 소켓 인터페이스를 통해 TCP 연결을 생성하고 HTTP 메세지를 주고 받는다.

무상태(Stateless) 프로토콜

서버가 클라이언트에게 데이터를 보낼 때 서버는 클라이언트에 관한 어떠한 정보도 저장하지 않는다. 만약 특정 클라이언트가 몇 초 후에 같은 객체를 또 요청한다면 이전에 한 일을 기억하지 않으므로 그 객체를 다시 보낸다.

무상태 프로토콜은 상태를 유지하지 않으므로 서버 간 상태를 동기화할 필요가 없어 확장이 용이하다는 장점이 있다. 하지만 매번 클라이언트가 자신의 정보를 서버에게 알려줘야 하기 때문에 추가 데이터를 전송해야 하는 단점이 있다.

또한 로그인이 필요한 서비스라면 유저의 상태를 알고 있어야하기 때문에 완전한 무상태는 현실적으로 어렵다. 이 경우 쿠키, 서버 세션, 토큰 등을 사용해 상태를 유지한다.


3. 지속 연결, 비지속 연결

많은 애플리케이션에서 클라이언트와 서버는 여러 요구를 보내고 응답하면서 오랜 기간동안 통신한다. 이 때 일련의 요구를 하나의 TCP 연결로 처리하면 지속 연결 요구마다 TCP 연결을 생성하여 처리하면 비지속 연결이라고 한다,

1) 비지속 연결(Non-Persistent Connection)

http://www.someSchool.edu/someDepartment/home.index 경로의 데이터를 서버에 요청한다고 가정하자. 이 home.index의 HTML 파일은 10개의 웹 객체(이미지)를 참조하고 있다.

  1. HTTP 클라이언트는 HTTP 기본 포트 번호 80을 통해 www.someSchool.edu 서버로 TCP 연결을 시도한다.
  2. HTTP 클라이언트는 1단계에서 구축된 TCP 연결 소켓을 통해 서버로 HTTP 요청 메세지를 보낸다. 요청 메세지에는 /someDepartment/home.index 경로를 포함한다.
  3. HTTP 서버는 연결 소켓을 통해 요청 메세지를 받고 /someDepartment/home.index 객체를 가져온다.
  4. 객체를 응답 메세지로 캡슐화하여 클라이언트에 전송한다.
  5. 클라이언트가 응답 메세지를 받으면 TCP 연결을 끊고 받은 HTML 파일을 조사한다.
  6. 받은 HTML 파일의 참조 파일 하나 당 1~5단계를 반복한다.

이처럼 위의 예시에서 비지속 연결의 경우 11개의 TCP 연결이 생성된다.

단점

각 요청 객체에 대한 연결이 생성되어야 하므로 TCP 버퍼, 변수를 유지하기 위한 비용이 크다. 따라서 이 경우 수많은 클라이언트들이 요청하는 웹 서버에서는 심각한 부담을 줄 수 있다.

또한 각 객체는 두번의 RTT(Round Trip Time)가 필요하다. 연결 요청 시에 한번 주고 받고 객체를 요청할 때 한번 총 두번 주고받게 된다.

2) 지속 연결(Persistent Connection)

앞의 비지속 연결 예제에서 비지속 연결은 11개의 TCP 연결을 생성했다면 지속 연결은 웹 페이지에 있는 객체들을 하나의 연결로 가져올 수 있다. 또한 한 객체에 대한 응답을 기다리지 않고 바로 다음 요청을 보냄으로써 전체 시간을 절약하는 파이프라이닝 방식을 지속 연결에서 활용할 수 있다.

파이프라이닝(Pipelining)

img_1.png

기존 전송 후 대기 프로토콜은 하나의 데이터를 요청하면 응답이 오기 전까지 다른 데이터를 요청할 수 없어 이용률(utilization)이 낮다. 하지만 파이프라이닝을 활용하면 이전 요청에 대한 응답을 기다리지 않고 여러 개의 패킷을 전송할 수 있어 이용률이 증가한다.

파이프라이닝 데이터 전송 프로토콜에서는 다음을 고려해야 한다.

  1. TCP 순서 번호(Sequence Number) 범위가 커야 한다. 한 번에 여러 패킷을 전송하므로 여러 패킷 간 고유한 순서 번호를 유지하기 위해서는 범위가 크다.
  2. 각 송신 측과 수신 측은 오류 발생, 재전송 등에 대비하여 패킷을 버퍼링해야한다.
  3. 패킷이 여러 이유로 손상되거나 도착하지 않을 때 GBN(Go-Back-N)SR(Selective Repeat) 등의 프로토콜을 활용하여 해결한다.

GBN은 시작 지점부터 N개의 패킷을 보낸다. 이 때 N개 패킷 중 k번째 패킷에 대한 응답을 받지 못했을 경우 뒤의 패킷은 정상적으로 받았더라도 k번째 패킷부터 다시 N개의 패킷을 보낸다. 응답을 받지 못했다의 기준은 N개 중 첫 번째 패킷을 전송한 이후 특정 시간이 경과되었을 때 이다. 따라서 N개의 패킷을 보낼 때 하나의 타이머만 있으면 된다.

SR은 응답을 받지 못한 패킷만 다시 재전송하는 방식이다. 이 방식은 응답을 받지 못한 패킷만 재전송하면 되지만 각각의 패킷에 대한 시간 경과(timeout)를 측정해야 하므로 여러 타이머를 유지하기 위한 오버헤드가 있다.

Keep-Alive

1
2
3
4
HTTP/1.1 200 OK
...
Connection: Keep-Alive
Keep-Alive: timeout=5, max=1000

HTTP/1.0에서는 비지속 연결이 표준이였으므로 지속 연결 설정을 위해 활용되는 헤더이다. Connection: Keep-Alive로 지속 연결로 설정할 수 있다. HTTP/1.1에서는 지속 연결이 표준이므로 일반적으로 Keep-Alive 헤더가 필요하지 않다. 하지만 Keep-Alive 헤더에서 timeout(연결이 지속되는 최소한의 시간), max(연결이 닫히기 이전 전송될 수 있는 최대 요청 수)를 세밀하게 설정할 수 있다. HTTP/2에서 연결 유지에 대한 제어의 필요성이 떨어져 Keep-Alive는 사용하지 않는다.


4. HTTP 버전

HTTP 버전은 지속 연결, 비지속 연결과 큰 관계가 있다.

1) HTTP/1.0

비지속 연결을 표준으로 하는 HTTP 프로토콜이다. 비지속 연결의 단점으로 HTTP/1.1이 등장하였다.

2) HTTP/1.1

지속 연결을 표준으로 하는 HTTP 프로토콜이다. 참조 객체들을 한 번의 연결로 가지고 오므로 TCP 연결을 위한 오버헤드가 감소한다.

HOL(Head Of Line)

img_3.png

지속 연결 시 HOL 블로킹 문제가 발생할 수 있다. 파이프라이닝은 응답이 오기 전에 여러 개의 데이터를 미리 보내는 방식이지만 결국 서버에서는 순차적으로 처리된다. 따라서 크기가 큰 비디오를 먼저 가져오고 작은 객체들을 가져온다면 비디오를 가져오는 동안 작은 객체들도 함께 지연된다. 이 문제가 바로 HOL 문제이다.

병렬 TCP

HTTP/1.1에서 HOL을 해결하기 위해 병렬로 TCP 커넥션을 생성하여 도입하려는 시도가 있었다. 이는 HOL을 해결하는데 일부 도움을 줬지만 병렬 연결은 다음과 같은 문제가 있었다.

  1. 여러 커넥션을 유지하는데 오버헤드가 있었다.
  2. 각각의 TCP 커넥션이 별개의 혼잡 제어 알고리즘을 수행하므로 하나의 TCP 연결보다 혼잡 제어 수행 능력이 떨어진다.

3) HTTP/2

img_4.png

HTTP/1.1에서 HOL 문제를 해결하기 위해 병렬 TCP를 도입하였지만 이는 여전히 문제가 있었다. HTTP/2는 하나의 TCP 연결을 사용하여 병렬 TCP의 문제점을 해결하면서 객체를 프레임 단위로 분할하여 HOL 문제도 함께 해결하였다.

객체를 프레임단위로 분할한 후 각 프레임을 교차(interleave)하며 보낸다. (1번 객체 1번 프레임 -> 2번 객체 1번 프레임 -> 1번 객체 2번 프레임 -> …) 이렇게 되면 크기가 작은 객체는 크기가 큰 객체에 의해 지연되지 않는다.

이 외에도 HTTP/2에서 다음과 같은 개선 사항이 있다.

  • 이전에는 텍스트 기반이였으나 이진(Binary) 인코딩을 도입하여 더 효율적으로 전송할 수 있다.
  • 각 프레임을 교차할 때 우선순위를 지정하여 어떤 프레임을 먼저 보낼 것인지 지정할 수 있다.
  • 서버가 클라이언트 요청을 받지 않고 참조 객체들을 미리 함께 전송할 수 있다.(서버 푸싱)

4) HTTP/3

HTTP/2는 TCP 기반이므로 패킷 손실 복구는 여전히 모든 객체의 전송을 중단한다. 신뢰성을 중시하는 TCP 특성 상 중간에 패킷이 손실 되면 정상적으로 도착한 이후 패킷들도 손실된 패킷이 재전송될 때까지 대기하게 된다. 이 때 지연이 발생하게 되고 HTTP/2에서는 이를 해결하기 위해 여러 TCP 커넥션을 유지하는 방법을 도입할 수 있다. 하지만 이는 HTTP/1.1에서 TCP 병렬 연결과 똑같은 문제가 발생하게 된다.

HTTP/3는 UDP를 기반으로 하여 멀티플렉싱, 스트림별 흐름 제어 등 여러 고급 기능을 제공하는 QUIC 프로토콜을 사용한다.


Reference

https://aws.amazon.com/ko/compare/the-difference-between-lan-and-wan/

https://butter-shower.tistory.com/108

https://siahn95.tistory.com/161

https://velog.io/@rmaomina/network-http

https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Keep-Alive

James F. Kurose,Keith W. Ross 편저, 최종원 외 7인 옮김, 컴퓨터 네트워킹 하향식 접근 8판, 퍼스트북

This post is licensed under CC BY 4.0 by the author.