HTTP

HTTP 서버 (김영한 HTTP)

ho코딩 2024. 1. 6. 22:20
*공부한 내용을 복습하기 위해 작성한 내용이며, 중간에 옳지 않은 내용이 포함될 수 있음.*

 

전 시간에 URL을 통한 통신과정을 보며 HTTP 요청 메시지를 주고받는 모습을 볼 수 있었다, 

 

오늘은 HTTP 메시지에 대해서 알아보자. 

 

HTTP 메시지에는 정말 많은 것을 담을 수 있다.

  • HTML , TEXT
  • IMAGE, 음성, 영상 파일
  • JSON, XML (API)

위의 형식 등등 서버간에 데이터를 주고받을 때 대부분 HTTP를 사용한다. 

 

HTTP에도 발전 역사가 존재하는데,

그 중 HTTP는 HTTP/1.1 버전으로 가장  중요한 버전이다. 

(그 외에도 HTTP/2 ,  HTTP/3 버전이 있는데 HTTP/1.1을 베이스로 성능개선한 버전이다.) 

 

TCP / UDP에 대해서도 전 시간에 배웠었는데

HTTP 1.1버전, HTTP 2버전은 TDP 프로토콜 기반이고  (3-WAY-HANDSHAKE)

HTTP 3 버전은 UDP 프로토콜 기반이다 (단순 /빠름)

 

 

프로토콜은 브라우저에서 F12 -> NETWORK -> PROTOCOL을 보면 확인 할 수 있다. 

h2라고 써있는 것은 http/2 버전 , h3은 http/3 버전을 의미한다. 

 

HTTP 특징

먼저 HTTP의 클라이언트 서버 구조를 보면 

계속 보면서 알 수 있듯이, "요청->응답"의 구조를 가진다 (클라이언트 Request -> 서버 Response) 

 

그 중에서도 "무상태 프로토콜 (stateless)"의 특징을 가지고 있는데 

- 서버가 클라이언트의 상태를 보존하지 않는다는 의미이다. 

 

 예를 들어서 로그인의 경우 사용자가 로그인을 하여 쇼핑을 하는 상황에서 

사용자가 로그인을 하면 로그인한 클라이언트의 상태를 기억해두었다가 그에 맞는 응답을 보내줘야한다. 

그런데 만약 무상태 프로토콜이면 로그인을 하고 새로고침 또는 페이지를 넘어가면 서버에서 클라이언트가 로그인 한 

상황을 기억하지 못하고 또 다시 로그인을 해야하는 번거로움이 발생한다. 

 

Stateful (상태 유지)와 Stateless (무상태) 를 비교한 예시를 하나 보이자면 

Stateful(상태 유지) 
고객: 노트북 얼마에요? 
점원: 100만원 입니다. 
고객 : 2개 구매할게요.
점원 : 200만원 입니다. 카드/현금 중 어떤 걸로 결제하시겠어요?
고객: 카드로 결제할게요. 
점원: 감사합니다.

이 처럼 물 흐르듯 깔끔한 상태유지의 경우와 

 

Stateless(무상태)
고객: 노트북 얼마에요? 
점원1: 100만원 입니다. 

고객: 2개 구매하겠습니다.
점원2: ?? 어떤 물건을 2개 구매하시겠어요? 

고객: 신용카드로 구매하겠습니다.
점원3: ?? 어떤 물건을 몇 개 신용카드로 구매하시겠어요? 

 

보기만 해도 답답한 Stateless 상태가 있다. 

무상태 프로토콜은 물건을 구입하는 고객을 응대하는 점원이 계속 바뀌는 상황으로, 이전에 고객과 다른 점원이 어떤 대화를 나누었는지 알지 못하여 고객의 매 요청마다 그 전의 과정을 다시 반복해야한다. 

 

(그럼 http는 무상태 프로토콜이라고 했는데 안좋은거 아닌가요?) 

 

그럼에도  무상태 프로토콜에는 장점이 있습니다. 

 

상태유지(Stateful)의 경우에는 결국 중간에 점원이 바뀌면 안됩니다. 즉, 서버가 바뀌면 안됩니다. 

때문에 상태유지는 중간에 서버를 추가할 수도 없고,

서버에 장애가 발생한다면 그 클라이언트에 대한 정보가 날아갈 수 있습니다. 

 

 

 

반면 무상태 프로토콜은 

응답 서버 (점원)을 쉽게 바꿀 수 있고, 서버를 추가 투입하여 서버 증설이 가능합니다.

 중간에 서버에 장애가 발생한다면, 그냥 다른 서버에서 응답을 해주면 되기 때문이죠. 

 

하지만 위 예시처럼 소통의 오류가 발생할 수 있기 때문에 그 방법이 따로 마련되어 있습니다. 

 

이처럼 고객이 매 요청의 과정마다 그 전 과정의 내용을 계속해서 덧붙여 요청하면 됩니다. 

(물론 이렇게 되면 요청해야 하는 메시지의 양이 점점 늘어나기 때문에 데이터의 크기가 늘어납니다.) 

 

그리고 한계가 존재하는데 아까 든 예시처럼 "로그인"의 경우에는 반드시 상태유지를 해야하는 경우도 존재합니다.

 

그런 경우에는 "브라우저 쿠키"와 "서버 세션"등을 사용하여 상태 유지를 하고 

만약 상태 유지를 사용해야하는 경우가 있다면 반드시 "최소한"만 사용해야합니다. 

 

 

HTTP의 비 연결성

 

 

보통 서버는 한 개의 클라이언트를 응대하는 것이 아니라 여러 클라이언트의 요청을 받습니다. 

때문에 1개의 서버에는 여러 클라이언트와 연결이 되는데, 서버는 연결할 수 있는 자원의 양이 정해져 있습니다. 

 

만약 서버가 클라이언트와의 연결을 유지하는 모델이라면 

이처럼 클라이언트 1,2,3이 서버와 연결되어 있지만 정작 요청은 클라이언트 1만 하고 있고 

클라이언트 2와 3은 서버와 연결은 되어 있지만 요청을 하고 있거나 응답을 기다리는 상황은 아닙니다. 

그렇다면 서버의 자원이 낭비 됩니다.

 

(참고로 서버와의 연결 과정은 이전 시간에 공부했던 SYN->SYN+ACK->ACK)의 과정을 거칩니다) 

 

이와 반대로 연결을 유지하지 않는 모델이 있습니다. 

서버에 요청을 할 것이 있는 클라이언트만 서버와 연결을 하고 요청에 대한 응답을 받으면 연결을 끊습니다. 

 

이 2가지 모델 중 HTTP는 "연결을 유지하지 않는 모델"이며 일반적으로 초 단위 이하의 빠른 속도로 응답합니다. 

 

-- 이것이 가능한 이유는 만약 1시간 동안 수천명이 서비스를 이용한다고 하더라도 실제 서버에서 동시에 처리하는 데이터의 양은 수십개 이하로 매우 작기 때문입니다. 

 

--네이버에서 검색을 하는 사람은 1시간동안 수천명~수만명이겠지만 1초 단위로 본다면 "검색"버튼을 누르는 사람은 그것보다 훨씬 적겠지요

 

이렇게 HTTP는 서버 자원을 매우 효율적으로 사용할 수 있다는 장점이 있습니다. 

 

반면 문제점도 존재합니다. 

1. TCP/IP 연결을 새로 맺어야 한다 -> 3-WAY-HANDSHAKE 시간 증가 

2. 웹브라우저에서 사이트로 요청을 하게 되면 받아야할 자원이 많다. 

 

요청 한 번에 연결 한 번을 한다면, 매 요청마다  3-WAY-HANDSHAKE를 해야하는데 

요청마다 이 시간이 증가할 뿐더러, 웹 사이트 요청을 하게 되면 받아야할 자원이 무지 많기 때문에 

핸드셰이크 횟수도 그만큼 많아집니다. 

 

 

 

이런 번거로움은 "지속 연결"을 통해 해결할 수 있습니다. 

지속 연결은, 조금 더 융통성 있는 방법으로 매 요청마다 연결을 하는 것이 아니라 일정 시간을 정해두고 연결을 하는 것입니다. 적어도 웹사이트 하나에 필요한 자원들을 다 받는 시간 만큼은 

 

그렇게 되면 위처럼 시간이 꽤 절약되면서 서버 자원은 최대한 효율적으로 사용할 수 있습니다. 

 

하지만 우리가 흔히 "서버가 터졌다" 라고 하는 경우가 있죠. 

아까 네이버 예시를 든 것 처럼 무상태 모델은 짧은 시간동안 많은 사람의 요청이 하지 않을 것을 예상해놓습니다. 

 

그러나 같은 시간에 많은 사람이 딱 맞추어 서버에 동시에 요청하는 대용량 트래픽이 발생하는 순간이 있습니다.

예를 들면, 선착순 이벤트/ 명절 KTX 예약 / 학과 수강신청 등 

 

이런 경우에는 대용량 트래픽이 발생하기 때문에, 최대한 무상태를 유지하면 이런 대용량 트래픽에 대비하는 것이 

서버 개발자 입장에서 가장 까다로운 일입니다. 

 

근본적인 해결방법은 서버의 양을 그만큼 늘리는 것이겠지만 일시적인 현상 때문에 비싼 서버 장비를 늘리는 것은 

비 효율적이기 때문에, 이용자가 최대한 몰리지 않게 하는 방법을 사용해야 하는 것이 최선입니다. 

 

 

 

HTTP 메시지

 

 

 요청을 할 때 주고받는 HTTP 메시지는 기본적인 구조가 있습니다. 

-시작라인 

-헤더 

-공백라인 ( 말 그대로 아무것도 없는 공백라인) 

-메시지 바디 

 

요청/ 응답 메시지는 보통 이런 구조를 가집니다. 

 

시작라인(빨간 박스)

 

1. 요청 메시지 

시작라인 = GET /search?q=hello&hl=ko HTTP/1.1 

-> HTTP 메서드 (GET : 조회)

    메서드에는 크게 GET / POST / PUT / DELETE가 있다. (추후에 다룰 예정)

 

->요청 대상(  /search?q=hello&hl=ko)

    절대경로 = "/"로 시작하는 경로 

 

->HTTP 버전 ( HTTP/1.1 )

 

2.응답 메시지 

시작라인 = HTTP/1.1 200 OK 

-HTTP 버전 = HTTP/1.1

-HTTP 상태 코드 = 200(성공) 의미 

-이유 문구 = OK (상태 코드를 알아볼 수 있게 자연어로 표시) 

 

헤더(노란 박스)

->  HTTP 전송에 필요한 모든 부가정보 ( 메시지 바디 내용, 크기, 압축, 인증, 클라이언트 정보, 캐시 관리 정보 .,..) 

 

요청 메시지 

HOST: www.google.com  (호스트주소) 

 

응답 메시지 

Content-Type: text/html;charset=UTF-8 (타입)

Content-Length: 3423 (크기) 

 

HTTP 메시지 바디(파란 박스)

-실제 전송할 데이터 / HTML 문서, 이미지, 영상 등등 Byte로 표현할 수 있는 모든 데이터 전송 가능