kiwi

HTTP 의 진화

by 키위먹고싶다

web

HTTP 의미 

먼저 사전적 의미의 HTTP란,

HTTP(HyperText Transfer Protocol)는 클라이언트와 서버 사이에 이루어지는 요청/응답(request/response) 프로토콜이다. 예를 들면, 클라이언트인 웹 브라우저가 HTTP를 통하여 서버로부터 웹페이지(HTML)나 그림 정보를 요청하면, 서버는 이 요청에 응답하여 필요한 정보를 해당 사용자에게 전달하게 된다. 이 정보가 모니터와 같은 출력 장치를 통해 사용자에게 나타나는 것이다. HTTP를 통해 전달되는 자료는 http:로 시작하는 URL(인터넷 주소)로 조회할 수 있다.

 

한마디로 월드와이드웹(www) 안에서 html과 같은 문서를 약속한 형식으로 통신하자고 만든 구조가 http인것이다. 이러한 http의 진화 과정을 살펴보자.


HTTP의 구조

http의 진화 과정을 살펴보기 전에 http의 구조를 간단하게 정리하겠다.

http는 Request(요청)와 Response(응답)하는 형태이다.

request메세지는 3부분으로 나뉜다.

  • start line(Request Line)
  • headers
  • body

response메세지도 3부분이다.

  • status line
  • headers
  • body

요청과 응답메시지에 중복으로 포함되는 헤더와 바디를 제외한 startLine과 StatusLine에 대해 먼저 알아보자.

 

요청 Request Line은 3가지로 나뉜다. 

  • HTTP Method => 어떤 action인지 (ex > get, post...)
  • Request target => 어디에 전송되는지 (ex > /main/login)
  • HTTP Version => 무슨 버전인지 (ex > 1.0, 1.1, 2.0...)

HttpRequest의 첫번째 라인에 

만약 GET /main/login/2.0이라고 적혀 있으면 get메서드를 이용해서 /main/login에 2.0버전을 사용해서 요청하겠다는 의미이다. 

 

응답 status line도 3부분으로 나누면

  • HTTP Version => 무슨 버전인지 (ex > 1.0, 1.1, 2.0...)
  • StatusCode => 응답 상태를 나태나는 코드. 숫자로 되어있음. (ex > 200 / 성공적으로 응답했다!)
  • StatusText => 응답상태를 설명해줌. 간략하게 (ex > 404면 'Not Found')

 

 Header와 Body

hearder와 body는 사진처럼 이해하면 되는데 헤더의 종류는 세가지이다. 

  • General Header => http본문 컨텐츠와 관련없는 요청/응답이 생성된 날짜 및 시간과 같은 HTTP통신에 대한 일반적인 정보가 포함된다. 요청과 응답메세지에 공통으로 사용된다.

 

  • Request/Response Header => 서버에 요청할때 RequestHeader는 요청한 url, method, 요청 생성에 사용된 브라우저의 정보등이 포함된다. 브라우저를 user-agent라고 한다. 현재 사용중인 브라우저 및 운영체제에 대한 정보를 전송하는 것이다. 위의 헤더부분에서 windows10 , chrome브라우저를 사용하고 있음을 알 수 있다. 그리고 Header는 'key : value'형태로 표현되는데 저기서 key는 'user-agent'이고 value는 ':'뒤에 있는 브라우저 정보이다. 헤더의 모든 정보는 이 형태다.  (key":" OWS value --> key와 ":"는 띄어쓰기 허용 안함, ":"와 value사이는 띄어쓰기 허용함. OWS는 띄어쓰기 허용한다는 뜻) ResponseHeader는 서버가 브라우저에 의해 수신되며 컨텐츠에 사용된 인코딩, 서버에서 응답을 생성할때 사용되는 서버 정보가 포함된다. (ex > server : NWS / 네이버에서 응답하는 서버 정보)

 

  • EntityHeader => 실제 메시지 또는 전송중인 HTTP 본문에 대한 정보가 포함된다. 컨텐츠 타입, 컨텐츠 길이, 컨텐츠 언어, 인코딩,등과 같은 중요한 정보. 최근에는 표현(Representation)헤더라고한다.  

body에는 실제 메시지의 본문이 나타난다. html코드나 이미지, css스타일 시트, JS파일 등등이 포함된다.  

 


HTTP_0.9

http/0.9는 http가 처음나왔을때 버전이다. http가 처음 나왔을때는 1.0이나 2.0과 같은 번호가 없었다. 0.9는 나중에나온 버전들과 구별하기 위해 붙은 이름이다. 처음버전은 요청 경로가 GET메서드만 가능했다. 응답또한 오로지 파일 내용 자체로만 구성된다. 이버전은 헤더자체가 없다. 오로지 html파일만 전송되며 다른 컨텐츠들은 전송하지 못한다. 상태코드나 오류코드가 없어서 문제가 발생할 경우 해당 파일 내부에 문제에 대한 설명이 응답됐다.


HTTP_1.0

이 버전부터는 버전 정보가 요청에 전송되기 시작했다. 그리고 상태코드라인도 응답의 시작 부분에 붙어 전송되었고 그로 인해 브라우저가 요청에 대한 성공과 실패를 알 수 있었다. 헤더의 개념이 처음 등장했는데 html파일 외에 다른 문서들을 전송하는 기능이 추가되었다. (ex > content-type : image/png)


HTTP_1.1 - 표준 프로토콜

HTTP의 첫번째 표준 버전이다. 1.0이 나온지 얼마 안돼서 공개된 버전이다. 1.1은 다음과 같은 특징이 있다.

 

1. 커넥션 유지(Persistent Connection)

그림처럼 HTTP1.0은 요청마다 TCP 세션을 맺어야 한다. (1 GET 1 Connection) 그런데 1.1은 유지기능을 이용해서 한개의 TCP 세션을 통해 여러개의 요청이 가능하다. (N GET 1 Connection) 이 차이는 서버가 TCP세션 처리에 대한 부담을 줄 일 수 있고, 그만큼 클라이언트의 응답속도가 개선된다. 

 

2. 파이프라이닝 (Pipelining)

HTTP 요청은 순차적으로 이루어지는데 파이프라이닝 기능이 없는 경우는 왼쪽 그림처럼 요청@1 > 응답@1 > 요청@2 > 응답@2 으로 진행된다. 요청 1에 대한 응답을 받은 뒤 요청 2가 진행된다. 파이프라이닝 기능은 이를 개선한 것인데 오른쪽 그림을 보면 요청 1,2가 동시에 진행되며 각 요청에 대한 응답이 돌아온다. 첫번째 요청에 대한 응답이 완료되기 전에 두번째 요청을 전송할 수 있으므로 커뮤니케이션 레이턴시를 낮출 수 있다. 

 

3. 호스트 헤더(Host Header)

1.0버전에서는 호스트 뒤에 경로만 요청 메세지에 담겨 보내고 HTTP프로토콜로는 host주소를 주고받지 않는다. 가상호스팅(하나의 서버IP에 여러개의 도메인을 둠)같은 경우는 어떤 호스트로 접근할 것인지 알아야 하는데 host주소를 주고받지 않는 1.0에서는 이것을 알 방법이 없다. 그래서 HTTP 1.0환경에서는 하나의 IP에 여러 개의 도메인을 운영할 수 없었고 도메인 마다 각각의 IP주소가 필요해서 도메인 수 만큼 서버의 갯수가 늘어 날 수 밖에 없다. 1.1환경에서는 Host Header를 둠으로써 가상호스팅이 가능하다. 

 

Host header 사용

Telnet www.naver.com 80 (호스트 : 주소 [ : 포트 ]) 


HTTP_2.0 

 HTTP 2.0은 1.1의 성능을 개선하는 방향으로 발전했다. 1.1에는 다음과 같은 문제점들이 있었다.

  • HOL Blocking : 앞의 요청에 의해 뒤에 요청이 지연되는 현상. 1.1의 파이프라이닝을 통해 한번에 여러개의 요청을 보내는 상황에서 앞선 요청에 대한 응답이 지연되면 그 뒤에 요청들의 응답이 모두 지연된다. TCP는 요청을 받은 순서대로 응답하기 때문이다. 
  • 무거운 Header :  클라이언트와 서버간에 수많은 요청이 발생하는데 이때 header정보가 대부분 비슷하지만 1.1은 헤더를 중복해서 계속 보내기 때문에(ex > 쿠키) 불필요한 데이터를 주고 받아서 네트워크 자원이 소비된다.  

이러한 특징들 때문에 속도가 느릴 수 밖에 없다. 그래서 2.0이 나오기 전까지 이미지 스프라이트(이미지를 하나로 합쳐서 리소스 요청을 한번만 보내기)나 css와 javascript파일을 압축해서 보내기 등 다양한 시도를 했다.

 

 2.0은 성능뿐만 아니라 속도도 1.1보다 월등하다. 

 

  • Multiplexed Streams : HTTP2.0에는 frame이라는것이 존재한다.(가장 작은 단위) 이 frame 2개가 합쳐지면 stream이다. (header frame + data frame) 한 커넥션에서 여러개의 메시지(프레임의 전체 시퀀스)를 주고 받을 수 있으며, 응답이 순서에 상관없이 stream으로 주고 받게 된다.

 

  • Server Push :  클라이언트가 요청하지 않은 리소스를 서버가 마음대로 보낼 수 있다. 클라이언트가 여러개의 리소스(CSS, Image)가 포함되어 있는 HTML문서를 요청 하고 응답 받은 후에 HTML문서를 해석하면서 필요한 리소스를 재요청한다.(HTML_1.1일 경우) 그러나 HTML2.0에서 Server Push기법을 사용해서 클라이언트가 요청한 HTML문서에 포함된 다른 리소스들을 요청 없이 Push해줌으로 클라이언트의 요청을 최소화 시킨다. 

 

  • Header Compression : 1.x시절에 요청마다 헤더에 중복된 값이 들어가도 전송됐다고 했다. HTTP2.0은 헤더에 중복값이 존재하는 경우 static/Dynamic Header Table 개념을 사용하여 중복 Header를 검출하고 중복된 Header는 index값만 전송하고 중복되지 않은 정보 값은 Huffman Encoding 기법으로 압축하여 전송한다. (Huffman coding은 무손실 압축 알고리즘으로 출현빈도를 기준으로 코드를 부여한다. 자주 나오는 문자에 짧은코드를 부여하고 상대적으로 적게 나오는 문자에는 긴 코드를 부여한다) 헤더를 압축하여 프로토콜 오버헤드를 최소화한다.

HTTP_3.0

HTTP3.0과 기존버전들의 가장 큰 차이점은 TCP가 아닌 UDP기반의 프로토콜인 QUIC(Quick UDP Internet Connection)을 사용하여 통신하는 프로토콜이라는 것이다. TCP와 UDP의 차이를 이론적으로 말하자면 'TCP는 신뢰성이 보장되고 느리다, UDP는 신뢰성이 낮고 빠르다' 라는 것이다. 신뢰성이란 전송되는 데이터들의 패킷순서, 패킷 유실 여부 등을 검사하여 송신측이 보낸 모든 데이터가 수신측에 얼마나 정확하게 전달될 수 있는지를 뜻한다.

 

TCP의 문제점

 

TCP는 통신을 시작 할 때 3 Way Handshake 방식을 사용한다. 클라이언트와 서버가 처음 통신할때 SYN과 ACK패킷을 주고받는다. 이 패킷 내부에 있는 값들을 사용해서 둘 사이에서 교환된 패킷의 순서와 패킷의 수신여부를 확인할 수 있다. 이때 주고받는 패킷들을 간단히 설명하자면

  • SYN :  연결을 생성할 때 클라이언트가 서버에 시퀀스 번호를 담아 보내는 패킷.
  • SYN-ACK : 시퀀스 번호를 받은 서버가 ACK값을 생성하여 클라이언트에게 응답하는 패킷. 서버는 클라이언트가 보낸 시퀀스 번호를 1증가시켜 ACK를 생성한다.
  • ACK : ACK 값을 사용하여 응답하는 패킷. 클라이언트가 서버로부터 1증가된 시퀀스번호를 받고 그 번호를 다시 1증가시켜 서버에게 보낸다.

새로운 TCP연결을 할때 클라이언트가 서버에게 랜덤한 시퀀스 번호를 전송하는 시점에 3 Way Handshake가 시작된다. 이 과정을 통해 양측이 서로 통신준비가 됐다는 것을 알리고 나서 통신이 시작된다. 그니까 TCP를 사용하면 이 번거로운 과정을 계속 거쳐야 하기 때문에 느리다는 것이다. 

 

TCP를 사용한 패킷은 무조건 정확한 순서대로 처리된다. 그래서 중간에 패킷이 손실된다면 완전한 데이터가 완성되지 않고 그냥 넘어가지 않는다. 무조건 송신측에서 수신측이 온전한 패킷을 받았다는 것을 확인하기 때문이다. 만약 패킷을 수신측이 제대로 받지 못하면 재전송한다. 또한 패킷이 처리되는 순서가 정해져있기 때문에 이전 패킷을 처리하기 전에는 다음 패킷을 처리할 수 없다. 패킷 유실이나 수신속도에 문제가 생긴다면 통신에 병목현상(HOLB)이 생길 수 밖에 없는데 이것은 TCP프로토콜이 자체적으로 가지고 있는 문제라서 TCP를 사용했던 2.0까지는 완전한 해결을 하기 힘들다.   

 

UDP를 사용하는 진짜 이유

 

UDP는 패킷 간의 순서가 존재하지 않는 독립적인 패킷을 사용하는 데이터그램 프로토콜이다. 패킷의 목적지만 필요하기 때문에 종단간의 연결 설정을 하지 않는다. 그러니까 TCP처럼 핸드쉐이크 과정이 필요하지 않다. 

 

UDP가 속도가 빠른건 알겠는데 기존의 TCP가 가지던 신뢰성을 놓친다는 말이 있는데 사실 그렇지 않다.

TCP의 단점을 보완하기 위해 개발자들이 오래전에 설계된 TCP프로토콜을 건드리는 것은 쉽지 않으며, 이미 신뢰성 있는 연결을 위해 헤더가 꽉 차 있기 때문이다. 반면에 UDP는 데이터 전송 자체에만 목적을 두고 있어서 헤더에 출발지와 도착지, 패킷의 길이, 체크섬 외에는 텅 비어있다. 그러니까 TCP가 가지고 있던 기능을 구현할 수 있는 커스터마이징을 할 수 있으며, 개발자의 능력에 따라 TCP와 비슷한 수준의 기능을 가질 수 있는 것이다.  

 

HTTP_3.0의 특징

 

연결 설정에 필요한 지연시간 감소

 

위에서 설명한 것처럼 서버와 클라이언트 통신을 위해 HTTP 연결 과정(핸드쉐이크) 과 TLS라는 암호화 과정까지 거치고 난 뒤에 요청이 시작된다. UDP를 사용하는 QUIC을 사용하면 클라이언트가 서버에 신호를 보내고 서버가 응답하면 바로 통신을 시작 할 수 있다. 그래서 연결 설정에 소요되는 시간이 매우 단축된다. 이게 가능한 이유는 TCP처럼 연결과 암호화에 대한 정보를 교환하고 확인받은 뒤에 통신을 시작하는 것이 아니라 첫번째 핸드쉐이크에 연결 설정을 위한 정보와 데이터를 함께 보내기 때문이다. 

 

멀티플렉싱(Multiplexing)

 

단일 연결로 여러 스트림을 사용하다보면 특정 스트림의 패킷이 손실될 수 있는데 이 손실된 애들이 다른 애들한테 영향을 미치지 않게 지킬 수 있기 때문에 TCP의 단점인 HOLB(모든 요청에 영항을 미침)를 해결할 수 있다. 손실된 패킷은 데이터가 손실된 요청에만 영향을 미치게 한다. 

 

유연한 네트워크 전환

 

TCP의 경우 네트워크를 전환하면 커넥션을 유지할 수 없는데 QUIC는 서버에 대한 연결을 고유하게 식별하는 연결 식별자가 포함되어 있어서 IP주소가 변경되더라도 커넥션을 유지 할 수 있다. 그래에서 서 HTTP3.0을 사용하면 네트워크가 변경될 때도 오류가 나지 않게 사용할 수 있다.   

 

 

지금까지 HTTP의 진화 과정을 살펴 보았다. 통신 구조는 참 어려운것같지만 신기기도 한것같다. 

'web' 카테고리의 다른 글

csrf 방지 기법  (0) 2022.06.06
HTTP와 HTTPS의 차이점에 대해서 알아보자  (0) 2022.01.14

블로그의 정보

kiwi

키위먹고싶다

활동하기