HTTP 1-2-3 + HTTPS
— HTTP — 5 min read
서론
웹 성능 최적화 스터디를 참여하고 있는데, HTTP 의 역사가 나왔다. 머릿속에서 휘발되기 전에 하나의 개념으로 묶어놓는 편이 나에게 유리할 것 같아 정리하는 HTTP 1-2-3 그리고 HTTPS 까지!
HTTP 란
지금 보고 계신 이 웹을 확인하기 위해서 HTTP 를 사용해서 콘텐츠가 전달이 되었을 텐데 🙂 그만큼 HTTP 너무 가깝고 쉬운 존재같지만 그래도 알아보자. HTTP(hypertext transfer protocol) 은 말그대로 '하이퍼텍스트'를 '전달' 하는 '규약'이다. 상호간에 하이퍼 텍스트를 어떻게 전달할지 정해놓은 약속이라는 말. 그럼 하이퍼텍스트는 뭘까? 하이퍼텍스트는 참조, 즉 우리가 흔히 링크라고 말하는 하이퍼링크를 포함한 텍스트를 말한다. hyper, 라는 말이 초월 이라는 뜻 말고도 건너편 이라는 뜻이 있기때문에 건너갈 수 있는 징검다리 형태의 텍스트가 머릿속에 떠오른다.
OSI 7 레이어로 하면 가장 위쪽 7계층에 위치해 있는 애플리케이션 계층 프로토콜이기도 하다.
0.9부터 3까지
0.9 의 탄생
웹버지 팀 버너스리 (Tim Berners-Lee)는 1989년 인터넷 상의 하이퍼텍스트를 교환하기 위한 네트워크를 만드는 데 골몰했고, 1990년이 되면서 이것의 이름은 mesh 에서 WWW(World Wide Web) 으로 변경되었다. 이때 WWW 를 기본 구성하기 위한 네가지 조건이 있었는데,
- 하이퍼텍스트 문서를 구성하기 위한 언어 - HTML
- 문서를 교환하기 위한 간단한 프로토콜 - HTTP
- 문서를 보여주기 위한 클라이언트 - WWW (브라우저로서)
- 문서에 접근할 수 있도록 해주는 하이퍼 텍스트 전송 서버- httpd
이렇게 초기 단계의 HTTP 는 매우 단순했고, 구분자로서 0.9 버전을 부여했다. one-line 프로토콜이라고도 불리는데, 요청이 단일 라인으로 구성되었기 때문이다.
리소스에 대한 HTTP method 는 GET 이 유일했고, 응답 또한 파일 내용으로만 올 수 있었다.
헤더도 없었는데, 따라서 HTML 파일만 전송될 수 있었음을 의미한다. 상태도, 오류코드도 없었다.
HTTP 는 0.9 버전 (보통 HTTP/0.9 와 같이 표기) 이후로 HTTP/3 까지, 여섯 차례에 메이저 업데이트가 있었다.
HTTP/0.9는 클라이언트와 서버사이의 인터넷 통신 정상화, 가용성, 신뢰성 등 기능에 초점을 두었다면, HTTP/1.0 부터는 클라이언트와 서버 사이의 요청과 응답을 빠르게 할 수 있는 연구가 진행되었다.
HTTP/1.0 - 최소한 클라-서버 요청으로 기능하게
HTTP/1.0 부터는 단순한 클라이언트와 서버 사이의 요청으로는 충분한 기능들이 본격적으로 담기기 시작했다.
- 1.0 이라는 버전 정보가 각 요청에 전송되기 시작했음.
- 상태 코드도 생겼다. 그래서 요청에 대한 성공, 실패를 알 수 있고 그에 맞춰서 어떤 동작을 할지 결정할 수 있게 되었음.
- 헤더 개념이 도입되어서, 메타데이터 전송을 허용할 수 있게했다. 더이상 HTML 파일만 전송하지 않아도 돼.. 🥹
HTTP/1.1 - 연결 재사용과 멀티 호스트 환경 지원
HTTP 1.0 은 구현이 여러군데서 진행되어서, 표준화가 필요했다. HTTP 1.0 을 개선하고 표준화해서 나온 첫 버전인 1.1 은 생각보다 많은 개선이 있었다.
HTTP/2까지 사용하는 TCP / IP 연결은 3-way handshake가 있어 매 연결마다 3번 통신이 발생한다. 그런데 HTTP 1.0 까지는 매 요청마다 이 handshake 과정을 모두 거치게 되어, 많은 웹 콘텐츠를 전달할 때 번거로움이 발생했다.
1.1에서는 커넥션 재사용을 통해서 커넥션을 다시 맺기 위해 필요한 3-way handshake 를 절약(!) 했다. 이를 HTTP 지속적 연결 (keep-alive / 연결 재사용) 라고 한다. 1.1 부터는 헤더를 사용하지 않아도 기본적으로 모든 요청과 응답이 keep-alive 로 설정된다. 만약 1.0 기반 클라이언트가, keep-alive 지원 웹서버에 요청하면서 지속적 연결을 사용하길 원한다면 다음 헤더를 추가하면 된다.
지속적 연결을 사용하지 않으려면 아래 헤더를 포함하여 보내면 된다.
지속적 연결을 사용하면, 단일 시간동안의 TCP 연결 수가 줄어들어 서버의 CPU 나 메모리 자원을 절약할 수 있는 장점이 있지만, 서버에 연결된 모든 클라이언트가 TCP 연결이 계속 늘어나면 자원이 고갈되어 뒤에 들어온 클라이언트들이 접속하지 못하는 문제가 있을 수 있다. 따라서 요런점을 잘 고려해서 지속적 연결 기능을 사용할지 결정이 필요하다.
또한 파이프라이닝이 추가 되었는데, 첫번째 요청에 대한 응답이 오기 전 두번째 요청이 전송될 수 있도록 했다. 동시에 여러 요청을 보낼 수 있으므로 커뮤니케이션 레이턴시를 낮출 수 있었다.
그외에, 청크된 응답이 지원되거나, 추가적인 캐시 제어 매커니즘 도입, 언어/인코딩 관련 콘텐츠 헤더 추가 (Accept-Language / Accept-Encoding
) , Host
헤더 추가로 동일 IP 주소에 다른 도메인을 호스트할 수 있게 되었다.
HTTPS - 보안의 필요성 대두
SSL 이 뭐요 에서 알 수 있지만 HTTPS 는 HTTP over SSL 으로, 보안을 강화한 버전이다. 시간 상으로 HTTP/1.1 과 HTTP/2 사이에 있다. 넷스케이프 커뮤니케이션은 기본적인 TCP/IP 스택을 사용하는 대신에, 그 위에 암호화된 전송 계층인 SSL 을 얹기로 했다. SSL 은 결국 TLS 라는 이름으로 표준화되었다. HTTPS는 전송계층을 결국 TCP+TLS 라는 개념으로 설명하곤 한다.
HTTP 통신 자체는 일반 텍스트로 이루어지므로, 도구만 있으면 누구나 쉽게 접근할 수 있고 경로 상 공격에 취약하다. HTTPS 를 사용하면 트래픽이 암호화되므로 패킷을 스니핑하거나 가로챈다고 해도 무의미한 문자로만 인식된다.
HTTPS 를 사용하는 서버의 웹페이지에 연결하면, 웹 페이지에서 보안 세션을 시작하는데 필요한 공개키가 들어있는 SSL 인증서를 전송한다. 그런 다음 클라이언트와 서버가 SSL/TLS 핸드셰이크를 진행한다.
HTTP/2
몇 년을 걸쳐서, 웹 페이지는 정말 정말 복잡한 애플리케이션이 되어버렸다. 웹에서 이미지를 편집하고 3D 모델을 만들어내기도 하니, 이해가 된다. 디스플레이되는 시각적 미디어의 양은 계속 늘어나고, 상호작용을 더해주는 스크립트의 양과 크기도 계속해서 늘어났다. 😨 그런데 여태까지의 HTTP 는 TCP 를 기반으로해서 순서가 보장되는 요청을 필요로 했다. 이때문에 HTTP/1.1 에서도 하나의 요청에 응답이 지연되면 나머지 모든 요청이 지연되는 문제가 있었다. 이를 HOL(Head-Of-Line Blocking) 이라고 한다. HTTP/2 와 HTTP/3 은 독자적인 HTTP HOL 기능을 선보였다.
HTTP/2의 전신은 구글에서 만든 SPDY 프로토콜이다. 이는 텍스트 방식의 프로토콜 메시지를 과감히 버리고 이진 포맷 (binary format) 을 사용했다. 그래서 HTTP/2 는 헤더프레임 과 데이터 프레임으로 나뉜다. 읽을 수는 없지만, 새로운 최적화 기술을 적용할 수 있는 형태로 변형된 것이다.
- 프레임: HTTP/2 통신 상 가장 제일 정보 단위이며 헤더나 데이터 중 하나!
- 메세지: HTTP/1.1 과 마찬가지로 요청 혹은 응답 단위이며 다수의 프레임으로 이루어져있음
- 스트림: 클라이언트와 서버 사이 맺어진 연결을 통해 양방향으로 주고 받는 하나 혹은 복수의 메시지
좀 헷갈릴 수 있지만 프레임 -> 메시지 -> 스트림 구조. HTTP/2에서는 스트림이라는 단위로 요청과 응답이 하나의 단위로 묶일 수도 있는 구조가 만들어졌다. 스트림에는 고유 번호가 있고 클라이언트는 응답 스트림 번호를 통해 어떤 요청에 대한 응답인지 파악한다.
HTTP/2의 구조가 유연해서, 서버에서 만들어진 응답 프레임들은 요청 순서에 따라 만들어진 순서대로 클라이언트에 전달될 수 있다. 즉 하나의 TCP 연결 상에서 다수의 클라이언트 요청과 서버 응답이 비동기 방식으로 움직이며, 이 기술을 멀티플렉싱 이라고 명명한다. 즉, 순서를 제거해서 HTTP/1.1 에서 생겼던 HOL 문제를 해결해주었다. 그러나 TCP 가 가지는 순서보장의 문제를 해결한 것은 아니고, 스트림이라는 개념을 도입해서, 윗단에서의 해결이다! 🤔 멀티플렉싱을 통해서 크기가 크거나 처리가 오래 걸리는 콘텐츠를 전달할 때 생기는 병목 현상을 풀 수 있게 되었다.
또 한가지 HTTP/2 의 특징..
데이터의 중복 전송, 그리고 중복 헤더 값들을 걸러내고 기존과 다른 방식으로 압축해서 오버헤드를 줄였다.
HTTP/1.1 까지는 Content-Encoding
을 통해서 결정된 알고리즘을 사용해서 HTTP 페이로드를 서버에서 압축했다. gzip 이 대표적일 것이다. 다만 페이로드는 압축해서 받을 수 있는데, 헤더는 그대로 받는 단점이 있었다. HTTP/2 는 이를 가상 테이블을 만들어서, 동일하고 중복되는 값들을 테이블에 저장하고 참고하는 방식으로 중복 전달을 제거했다.
또 HPACK 이라는 헤더 압축 알고리즘을 도입해 허프만 알고리즘 방식으로 경량의 데이터를 주고받을 수 있게 됐다. 허프만 알고리즘은 문자열에 작은 코드 값을 부여하고, 중복되는 경우 코드를 전달하는 방식이다.
그리고 또한, HTTP/2는 서버 푸시라는 매커니즘을 사용해서, 클라이언트가 요청하지 않은 콘텐츠도 서버가 미리 빠르게 전송해서 RTT 를 줄였다. 이는 요청없이는 응답하지 않던 HTTP 프로토콜에 큰 혁신을 가져왔다. 서버 푸시의 대상은 웹 서버 관리자/개발자가 미리 정할 수 있다. 일반적으로 HTML 호출 후, 해당 페이지가 호출하는 js / css 가 고정되어있다면 서버 푸시대상으로 지정하는 것이 유리하고, 미리 설정할 수 있다.
HTTP/3
HTTP/3 은 HyperText Transfer Protocol over QUIC 을 바탕으로 해서 등장한 HTTP의 세번째 주요 업데이트 버전이다. HTTP/3은 전송계층에 TCP/TLS 대신 QUIC 을 사용하는데, 그럼 TCP 의 사용이 대체되었다는 생각을 해볼 수 있다.
그럼 왜 대체했을까? TCP는 역사가 깊은 프로토콜로, 전달의 성능보다는 기능에 초점을 두었다. 모두들.. TCP는 순서보장, UDP는 속도여서 스트리밍에 쓴다 - 는 한 줄 정도는 기억하고 있을 것..! TCP는 그러므로 멀티미디어를 빨리 전달해야하는 이런 요구에 잘 안맞는 상황이었다. 또 HTTP/2에서 언급했지만 근본적으로 TCP 스택을 사용했으므로 TCP의 HOL 문제를 해결하지 못했다. 그래서 구글+IETF 에서 TCP의 높은 신뢰성과 UDP 의 빠른 성능을 토대로 차기버전의 연구를 계속해서 QUIC을 고안했다. 즉 HTTP/3은 HTTP/1.1 -> HTTP/2 에서 기능을 대거 추가한 것과 달리, HTTP/2 의 단점을 보완하는 데 중점을 두었다.
QUIC 은 Quick UDP Internet Connection 의 줄임말로, UDP 를 기반으로 구현된 다중 전송 프로토콜이다. 구글에서 개발했고, 전달 속도의 향상과 더불어 클라이언트와 서버 연결을 최소화하고 대역폭을 예상해 패킷 혼잡을 피하는 것이 특징이다.
HTTP/2 로 오면서 사실상 보안 웹 브라우징이 대거 도입되어, 표준 방식은 TCP + TLS 을 통한 통신이었는데, 이를 위해서는 TCP 연결 뿐아니라 보안 연결을 위해서 서버와 2-3회 정도 왕복해야한다. QUIC 은 클라이언트가 이전에 특정 서버와 통신한 적이 있는 경우, 이러한 왕복 과정이 없이 데이터 전송을 시작할 수 있도록 설계되어있다. 크로미움 블로그 의 데이터에 따르면 75% 연결이 초반 연결 수립 과정이 필요없어서 웹 페이지를 더 빠르게 연결할 수 있는 걸로 나타났다.
HTTP/3 을 사용하려면 HTTP/2 와 마찬가지로 웹 브라우저와 웹 서버 모두 HTTP/3 를 지원해야한다. 가장 친밀한 우리의 nginx는 2020년 HTTP/3 지원 프리뷰를 발표했다. 해당 블로그에 따르면 nginx 에서 QUIC+HTTP/3 를 활성화하려면 아래와 같이 할 수 있다.
마치며
구글 개발자 도구에서는 현재 사이트가 HTTP 버전 중 어떤 버전으로 통신하고 있는지 확인 가능하다. 네트워크 탭 에서 항목에 오른쪽 클릭으로 프로토콜을 추가한다.
- http://nghttp2.org/ 에서 HTTP/1.1을,
- https://www.naver.com 에서 HTTP/2를, (h2으로 표시)
- https://www.google.com 에서 HTTP/3 을 확인할 수 있다. (h3으로 표시)