Search
Duplicate

3. HTTP 기본

목차

모든 것이 HTTP

HTTP(Hyper Text Transfer Protocol)

: 문서간에 링크를 통해 연결할 수 있는 프로토콜
하지만, 이제는 문서뿐 아니라 HTTP 메세지에 모든 것을 전송한다.
HTML, TEXT
IMAGE, 음성, 영상, 파일
JSON, XML(API)
거의 모든 형태의 데이터가 전송 가능하다.
서버간에 데이터를 주고 받을 때도 대부분 HTTP를 사용한다.

HTTP의 역사

HTTP/0.9 1991년: GET 메서드만 지원, HTTP 헤더 X
HTTP/1.0 1996년: 메서드, 헤더 추가
HTTP/1.1 1997년: 가장 많이 사용하며, 우리에게 가장 중요한 버전
RFC2068(1997) → RFC2616(1999)(개정) → RFC7230~7235(2014)(개정)
1.1에 대부분의 기능이 들어갔고, 2와 3에서는 성능 개선에 초점이 맞춰져 있다.
HTTP/2 2015년: 성능 개선
HTTP/3 진행중: TCP 대신에 UDP 사용, 성능 개선

기반 프로토콜

TCP: HTTP/1.1, HTTP/2는 TCP 기반으로 동작한다.
UDP: HTTP/3
현재 HTTP/1.1을 주로 사용한다.
HTTP/2, HTTP/3도 점차 증가하고 있다.
어째서 HTTP/3는 UDP 기반이지?
⇒ 기존 TCP는 3 way hanshake부터 내부적으로 포함하거나 추가해야하는 작업들이 너무 많아서 신뢰성이나 연결성은 보장되지만 속도가 떨어진다. 그렇기에 UDP프로토콜을 애플리케이션 레벨에서 재설계를 해서 나오는게 HTTP/3이다.
크롬: 거진 다 h3를 사용하고 있다.
네이버: 아직 h1, h2도 혼용되고 있다.

HTTP 특징

클라이언트 서버 구조로 동작한다.
무상태 프로토콜(stateless), 비연결성
HTTP 메세지를 통해서 통신을 한다(송/수신 모두 )
단순함, 확장 가능

클라이언트 서버 구조

HTTP는 클라이언트와 서버 구조로 되어있는데, HTTP는 클라이언트가 HTTP 메세지를 만들어 보내고 , 서버에서 요청에 대한 응답이 올 때까지 기다린다.(Request) 그리고 서버는 요청에 대한 결과를 만들어서 응답(Response)하는 구조인데, 어째서 이렇게 클라이언트와 서버를 분리해야만 할까?

각자의 역할에 집중할 수 있다.

클라이언트에서는 복잡한 비즈니스로직이나 데이터를 다룰 필요없고, UI를 그리는데 집중할 수 있다.
서버에서는 복잡한 비즈니스로직이나, 데이터를 다루는데만 집중하면 된다.
⇒만약 트래픽이 폭주해 고도화가 필요한 경우 클라이언트는 신경쓰지 않고 서버만 개선하면 된다.

정리

클라이언트와 서버를 독립적으로 구분한다는 것은 각자의 책임을 나눠 해당 책임에만 집중하여, 이슈가 생기거나 할 때 한 쪽에만 신경쓰면 된다는 장점을 가진다.
그럼으로써 우리는 문제가 생겼을때도 빠르게 원인파악및 내가 찾아서 고치거나 추가해야하는 기능을 넣어야 하는 위치를 쉽게 찾을 수 있고, 더 많은 확장성과 유연성을 가질 수 있다.

Stateful, Stateless

Stateful, Stateless의 차이점

Stateful(상태 유지)

서버가 클라이언트의 상태를 보존한다.
즉, 클라이언트와 서버간에 송/수신을 하며 단계별 과정을 진행하는데 서버에서 클라이언트가 이전 단계에서 제공한 값을 저장하고 다음 단계에서도 저장한 상태인 것.
그럼 문제가 무엇일까? 서버가 멈추거나 하는 여러 이유로 해당 서버가 못쓰게되서 다른 서버를 사용해야 한다면 새로운 서버에서는 이전 서버에서 가지고 있던 상태값들을 가지고 있지 않기 때문에 에러가 발생한다.
예제
1.
서버가 문제없이 유지되는 경우
클라이언트: 변수 A에는 10을 넣어줘. 서버: 변수A에 10을 넣겠습니다. 클라이언트: 변수 B에는 20을 넣어줘. 서버: 변수 B에 20을 넣겠습니다. 클라이언트: 변수A와 B의 합은 뭐야? 서버: 변수의 합은 30입니다.
Plain Text
복사
2.
서버가 멈춰서 새로운 서버에 요청하는 경우
클라이언트: 변수 A에는 10을 넣어줘. 서버A: 변수A에 10을 넣겠습니다. --서버A 다운으로 서버B로 교체-- 클라이언트: 변수 B에는 20을 넣어줘. 서버B: 변수 B에 20을 넣겠습니다. 클라이언트: 변수A와 B의 합은 뭐야? 서버B: 변수의 합을 계산할 수 없습니다.
Plain Text
복사
새로운 서버로 변경되면서 기존 서버에 저장한 변수값을 새로운 서버에서는 알 수 없기에 에러가 발생한다.
(만약, 기존서버에서 새로운서버로 이전 데이터를 모두 전달해준다면 문제가 없을 수 있다.)
즉, 항상 같은 서버가 유지되어야 한다.

Stateless(무상태)

서버가 클라이언트의 상태를 보존하지 않는다.
그렇기에 매번 요청에 모든 상태값들을 전달해줘야 한다.
예제
클라이언트: 변수 A에 10을 넣어줘 서버A: 변수 A에 10을 넣겠습니다. --서버A 다운으로 서버B로 교체-- 클라이언트: 변수 B에는 20을 넣어줘. 서버B: 변수 B에 20을 넣겠습니다. 클라이언트: 변수A에 10을 넣고 변수 B에는 20을 넣고 곱을 계산해줘? 서버C: 변수의 합은 200입니다.
Plain Text
복사
스케일 아웃 - 수평 확장 유리
서버의 변경이 용이하다는 것은 같은 기능을 하는 서버 어느것을 선택해도 된다는 것.
그렇기에 서버의 수평 확장이 몹시 유리하다.

정리

상태 유지: 중간에 서버가 변경되면 안된다.
(만약 서버가 변경되야 한다면 상태 정보를 전부 다른 서버에게 미리 알려줘야 한다.)
무상태: 중간에 서버가 변경되도 된다.
클라이언트가 폭증해도 서버를 대거 늘릴 수 있다.
무상태는 응답 서버를 변경하기가 쉽기에 서버 증설이 쉽다.

무상태의 실무 한계

모든것을 무상태로 설계가 가능한 경우도 있고 없는 경우도 있다.
무상태
로그인이 필요 없는 단순한 이벤트 페이지
상태 유지
로그인을 해야하는 경우
로그인한 사용자의 경우 해당 상태를 서버에 유지해야한다.
일반적으로 브라우저 쿠키와 서버 세션등을 사용해 상태를 유지한다.
상태 유지는 최소한으로만 사용한다.
보내야 하는 데이터가 너무 많다.
⇒ 매번 요청에 필요한 데이터를 전부 작성해야 하기 때문.

비 연결성(connectionless)

TCP/IP는 연결을 유지하는 모델

TCP/IP는 연결을 유지하는 모델이다.
클라이언트1이 서버와 연결을 한 뒤 클라이언트 2에서 서버와 연결을 할 때도 클라이언트 1과 서버는 연결을 유지하고 있다. (이는 클라이언트 3의경우도 마찮가지다.)

연결을 유지하지 않는 모델

클라이언트별로 서버와 연결을 유지하지 않을경우 필요할때만 연결을 하며 그외에는 연결을 유지하지 않기 때문에 서버에서 사용해야 하는 자원이 훨씬 줄어든다.

HTTP의 비연결성

HTTP는 기본이 연결을 유지하지 않는 모델이다.
일반적으로 초 단위 이하의 빠른 속도로 응답한다.
1시간동안 수천명 이상이 서비스를 사용해도 실제 서버에서 동시에 처리하는 요청은 수십개 이하로 적다.
EX: 웹 브라우저 검색페이지에서 검색버튼만 연타하면서 이용하지는 않는다.
서버 자원을 매우 효율적으로 사용할 수 있다.

비연결성의 한계와 극복

비연결성이 좋기만 한 것은아니다. 매번 새로 연결해야한다는것은 매 연결마다 들어가는 비용에 대해서 고려하지 않을 수 없다.
TCP/IP 연결을 새로 맺어야 한다. - 3 way handshake 시간 추가
웹 브라우저로 사이트를 요청하면 HTML 뿐 아니라 JavaScript, CSS, Image등 수많은 자원들을 함께 다운로드한다.
지금은 HTTP 지속 연결(Persistent Connections)로 문제를 해결한다.
HTTP/2, HTTP/3에서 더 많은 최적화.

HTTP 초기 - 연결, 종료 낭비

HTTP 초기에는 모든 자료에 대해서 비연결성으로 각각의 자원에 대해 연결/응답/종료를 반복하다보니 대략적으로 1초가량 소모되었다고 한다. 그럼 이 경우 HTTP 지속 연결을 하면 어떻게 될까?

HTTP 지속 연결(Persistent Connections)

클라이언트는 서버와 연결을 한 다음 필요한 자원을 요청/응답으로 다운로드받는다.
그리고 초기와 차이점으로 연결이 종료되는 것이 아니라 필요한 자원들을 모두 다운받을때까지 연결이 종료되지않고 요청/응답이 반복된 뒤 종료된다. 그럼으로써 속도 자체가 더 빨라졌다.

스테이스리스를 기억하자.

실무상황에서 특정 시간에 발생하는 대용량 트래픽에 대해서 대응해야 하는 경우가 생긴다
(Ex: 선착순 이벤트, 명절 KTX예약, 개강전 수업 등록)
이럴 경우 수천, 수만명 이상이 동시에 접속을 하면서 서버에 과부하가 걸리는 경우가 있는데,
이 경우 무상태 페이지를 활용해 페이지 접속인원을 분산해서 대용량 트래픽을 분산시키면 좋다.

HTTP 메시지

위에서(1) HTTP로 모든 자원을 전송할 수 있다고 했다.
이 HTTP는 요청/ 응답 메세지가 약간 구조가 다르다.

HTTP 메시지 구조

공백라인은 필수정보.

HTTP 헤더

header-field = field-name":" OWS field-value OWS
⇒OWS: 띄어쓰기 허용
field-name은 대소문자 구분이 없다.

HTTP 헤더 용도

HTTP 전송에 필요한 모든 부가정보
메시지 바디의 내용, 메시지 바디의 크기, 압축, 인증, 요청 클라이언트(브라우저) 정보 등등.
표준 헤더가 너무 많다.
필요한 경우 임의의 헤더 추가 가능
helloworld: hihi

HTTP 메시지 바디 용도

실제 전송할 데이터
HTML문서, 이미지, 영상, JSON 등 byte로 표현할 수 있는 모든 데이터 전송이 가능하다.

HTTP 요청 메시지

요청 메세지의 시작 라인에 전송 타입과 패스, 쿼리스트링, HTTP 버전같은 정보를 담는다.
헤더에는 기타 정보를 담는다.
전송할 데이터가 없으면 공백 이후 무언가 추가할 필요는 없다.

시작 라인

start-line = request-line / status-line
request-line = method SP request-target SP HTTP-version CRLF
SP : 공백(Space)
CRLF: 엔터(개행)
HTTP 메서드(GET: 조회)
종류: GET, POST, PUT, DELETE
서버가 수행해야 할 동작을 지정한다.
GET: 리소스 조회
POST: 요청 내역 처리
요청 대상(/search?q=hello&hl=ko)
absolute-path[?query](절대경로[?쿼리])
절대경로 = "/"로 시작하는 경로
*, http://...?x=y와 같이 다른 유형의 경로지정 방식도 있다.
HTTP Version

HTTP 응답 메시지

시작라인에는 HTTP 버전과 Status Code등을 담는다
헤더에는 기타 정보를 담는다.
Body에 요청한 자원을 담는다. (ex: HTML)
공식 스펙
HTTP-message = start-line *(header-field CRLF) *CRLF [ message - body ]
Plain Text
복사

시작 라인

start-line = request-line / status-line
status-line = HTTP-version SP status-code SP reason-phrase CRLF
HTTP 버전
HTTP 상태 코드: 요청 성공, 실패를 나타낸다.
200: 성공
400: 클라이언트 요청 오류
500: 서버 내부 오류
이유 문구: 사람이 이해할 수 있는 짧은 상태 코드 설명 글

단순함 확장 가능

HTTP는 몹시 단순하고 스펙도 볼만하다.
HTTP 메시지도 매우 단순하다.
정리하면 단순하기에 확장이 쉽고 유연한 기술이다.

이전 챕터로

다음 챕터로