[10분 테코톡] 포이의 HTTP1.1, HTTP2, 그리고 QUIC 정리
HTTP란?
HyperText Transfer Protocol의 준말로 하이퍼 미디어 문서를 전송하기 위한 애플리케이션 레이어 프로토콜
하이퍼 미디어 문서란 웹상에서 돌아다니는 정보들, HTML이 될 수도 있고, 이미지 파일이 될 수도 있고, CS 파일이 될 수도 있는 그런 것들을 총칭하는 말이라고 알아두면 된다.
위 그림이 네트워크를 4개층으로 나눈 TCP/IP 4계층이다. 어플리케이션 레이어 같은 경우에는 최상층에 위치해 있는 걸 볼 수 있는데 정보를 주고 받고 하기 위해서는 하위계층을 반드시 지나야 한다. 그래서 어플리케이션 레이어의 HTTP를 설명하기 위해서는 전송계층에 대한 설명도 불가피하기 때문에 짧게 알아보자
TCP 같은 경우 연결형의 연결 방식을 택하고 있다. 연결형은 데이터를 주고받기 전에 다짜고짜 데이터를 보내는 것이 아니고 내가 서버랑 잘 연결이 됐는지 연결을 확인하는 과정을 거친다. UDP 같은 경우는 연결 과정이 하나도 없다. 일단 데이터 보내고 너 받았으면 오케이하고 끝이다. 그래서 TCP는 이런 연결과정 덕분에 데이터 전송의 신뢰성이 상대적으로 높지만 속도는 낮다고 할 수 있고 UDP는 TCP와 반대로 신뢰성은 낮은 대신 어느 정도 속도를 보장해줄 수 있다는 특징을 가지고 있다.
* 참고 : 칙촉의 TCP/UDP 정리
HTTP/1.0
- 단일 연결
- 단일 요청, 응답
1.0 같은 경우 기본적으로 tcp 연결하면 정보를 주고받고 다시 연결을 해제해야 하는 구조를 가지고 있다. 한 연결에 하나의 요청과 응답이 왔다 갔다 하는 것이다. 이것은 문제가 있는데 만약에 웹페이지를 로딩한다고 했을 때, html 파일을 요청하고 응답을 받았는데 보려고 하니까 이미지 파일이 필요하다. 그러면 다시 연결을 또 하고 이미지를 받고 또 연결을 해제해야 한다. 그런데 글씨체도 달라야 되서 CSS도 받아야 한다면 또 연결하고 또 해제하는 이런 비효율적인 과정이 있었다.
HTTP 1.1
- 전송 계층 프로토콜 tcp 를 사용
- http 1.0의 문제를 해결하기 위해 출시
- 2.0 출시전까지 약 15년간 주로 사용됨
● 지속적 연결
HTTP 1.1에서는 지속적인 연결을 기본으로 채택하여 연결 한 번에 HTML도 받고 받고 보니 이미지도 필요하면 이미지도 받는 이렇게 한 번에 받을 수 있게 되었다. 효율적이다.
● 파이프라이닝
HTML도 필요하고 이미지도 필요하고 CSS도 필요할 것 같으니 서버에 다 요청한다. 그럼 서버가 차례대로 응답을 해준다.
그러면 당연히 지연이 줄어들게 된다.
하지만 문제가 몇가지 있었다. 그중에 대표적인 두 가지 문제는 HOL Blocking과 중복 헤더이다.
1) Head Of Line Blocking (HOL Blocking)
위와 같이 이미지, CSS, HTML 요청을 한 번에 보냈다. 그런데 1번 요청에 대한 응답을 서버에서 처리하는데 10초가 걸리고 2번, 3번은 0.1초면 바로 보내줄 수 있다. 데이터베이스에서 꺼내서 보내주는 것인데 2번, 3번을 먼저 보내주면 좋지만 TCP는 그것이 안됀다. 블록을 해놨다가 1번 응답이 될 때까지 즉 10초가 지나고 응답이 되면 그제서야 보내줄 수 있는 비효율적인 문제가 있다.
2) 중복 헤더
HTTP를 공부했다면 알겠지만 HTTP 헤더에는 중복되는 자료들이 많다. 위에 request 1과 2는 다른 요청인데 path을 제외하고 다 똑같다. 중복이 계속 일어나게 된다.
이러한 문제를 해결하는 2.0이 15년에 등장하게 된다.
HTTP/2.0
▶ 바이너리 프레이밍 - HOL Blocking 해결
먼저 기본적으로 1.1은 텍스트로 모든 정보를 왔다 갔다 했다. 이제는 이 것을 바이너리로 인코딩을 한다. 텍스트보다는 바이너리를 컴퓨터가 더 좋아하니 처리 속도가 빨라질 수밖에 없다.
이것이 끝이 아니고 바이너리로 프레이밍이 된 것을 여러 개의 프레임으로 쪼갠다. 그러면 멀티플렉싱이 가능해진다.
예시를 들어보자면 A응답이 커서 6~7개 나누었고, B와 C는 2개 블록으로 나뉘었다고 가정한다. 그러면 A 보내고 B 보내고 C 보내고 A 2개 보내도 될거 같으면 보내주고 C 보내고 B 보내고 이런 식으로 보냈다. 그럼 A는 아직 많이 남았다. 그런데 여기까지 갔을 때 B랑 C에 대한 응답은 클라이언트 입장에서 완료가 된 것이다. 그렇다면 이것에 대한 정보를 미리 처리할 수 있어서 처리할 거 미리 해놓고 A는 나중에 오면 해야겠다고 할 수 있다. 즉 효율적으로 처리할 수 있게 되었다. 이렇게 HOL Blocking을 해결하였다.
▶ COMPRESSION HEADER - 중복 헤더 해결
어떤 정보를 사전에 보냈는지 정적 테이블에 미리 캐싱을 해놓는다. 그래서 필요하고 안 겹치는 정보만 빼서 전송하게 되어 헤더 크기가 많이 줄어들었다. 이것이 끝이 아니고 허프만 코딩이라는 방법으로 인코딩을 해서 한 번 더 크기를 줄인다. 이렇게 구조를 사용하다 보니 1.1에 비해서 2.0은 헤더의 크기가 약 85%나 줄어들었다고 한다.
하지만 2.0이 사실 1.1을 완전히 대체하자 라고 나온 것이 아니고 1.1의 성능을 향상시켜 지연을 줄여 보자고 해서 나왔는데 지연이 잘 안 줄었다.
왜 그럴까 생각을 해보니 고질적인 문제가 하나 있었다. TCP에서 동작을 하는 것이 문제였다. TCP가 왜 문제일까?
TCP에서도 HOL Blocking이라는 문제가 똑같이 발생한다.
위에 HTTP 계층에서 발생했던 것과 비슷한 문제인데 TCP에서 위와 같이 스트림이 멀티플랙싱 돼서 가고 있다. 그런데 C 응답에 대한 요청 패킷이 하나가 손실되었다. 그렇다면 TCP는 신뢰성을 중요시하는 프로토콜이라서 C를 재전송 해야된다. 그런데 재전송할 때까지 뒤에 나머지도 다같이 기다리고 있는다. A와 B는 먼저 받고 싶은데 C가 손실됐다고 비효율적으로 기다리고 있는 것이다. 그래서 이것은 TCP 자체의 문제다 이것은 HTTP로는 해결을 못한다 해서 구글에서 아예 전송계층 프로토콜을 새로 만들었다.
QUIC
QIOC는 UDP 위에서 동작하는 전송계층 프로토콜이다. 간단하게 이갸기 하자면 UDP 위에 QUIC 위에 HTTP를 올렸다라고 생각하면 된다.
▶ 독립 스트림
요청별로 다른 스트림을 써서 A응답이 블록이 돼도 A만 블록이 되고 다르 스트림은 영향이 없다. 이것으로 간단하게 HOL Blocking을 해결하였다.
▶ RTT 최소화
TCP 같은 경우 연결 과정이 있고 HTTPS를 사용할 때는 CLS 연결 과정이 한 번 더 필요하다. 그래서 위와같이 연결을 하고 나서야 데이터를 주고받을 수 있었다.
QUIC 입장에서는 어차피 너네 HTTP를 안쓰고 보안 있는 HTTPS 쓸 거잖아라고 해서 아예 얘를 탑재를 해버린다. 즉 첫 연결에 CLS 연결까지 다 끝낸다. 그리고 데이터 바로 주고받으면 당연히 빠르다.
여기에 Connection ID를 클라이언트한테 연결을 한 번 하면 부여를 해준다. 기존의 TCP는 IP랑 포트번호로 구별을 하는데 이경우 내가 서울에서 인터넷을 쓰다가 KTX 타고 부산 광주 내려왔다. 그러면 인터넷 권역이 바뀌게 된다. 즉 서울 인터넷 쓰다가 부산 인터넷 써야 되는 것이다. IP랑 포트번호는 당연히 바뀐다. 그러면 서버 입장에서는 이 놈 뭐지? 못 보던 앤데? 라고 해서 '다시 연결해 TLS 정보 다시 내놔' 하고 연결 과정을 똑같이 체결한다.
그런데 QUIC는 Connection ID로 구별을 해서 인터넷이 바뀌어도 이 패킷에 이 아이디를 헤더에 같이 실어서 보내버린다. 그러면 '너는 저번에 봤던 애 신뢰성 있는 애구나' 하고 응답을 그냥 줄 수 있게 된다. 효율적이다. 이것를 한 번 쓰고 버리지 않고 클라이언트가 캐싱을 한다. 그래서 다음 요청부터는 연결 과정이 아예 필요가 없게 된다. 그래서 현재 구글, 유튜브, 페이스북에서는 전부 다 QUIC 프로토콜을 지원한다. 그리고 QUIC 위에서 돌아가는 http를 http/3라고 한다.
참고
https://www.youtube.com/watch?v=Zyv1Sj43ykw&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9C%ED%85%8C%ED%81%AC