1. 라이브러리
  2. HTTP와 웹
  3. HTTP 기본 원리

업데이트됨 1개월 전

링크를 클릭할 때마다 광자가 광섬유를 통해 달려갑니다—때로는 대양을 가로질러. 뉴욕에서 도쿄까지 패킷이 왕복하는 데 최소 140밀리초가 걸리는데, 이는 최적화된 금융 네트워크 기준입니다1. 일반 연결은 더 오래 걸리죠. HTTP의 역사 전체는 그 지연을 받아들이지 않으려는 인류의 의지입니다.

이 프로토콜은 다섯 번 다시 쓰였습니다. 엔지니어들이 심심해서가 아니라, 각 버전이 벽에 부딪혔기 때문입니다. 그 벽들을—그리고 그것을 우회한 영리한 방법들을—이해하면, 물리 법칙이 변하지 않았음에도 왜 현대 웹사이트가 빠르게 느껴지는지 알 수 있습니다.

HTTP/0.9: 한 줄짜리 프로토콜

1991년, Tim Berners-Lee는 문서를 가져올 방법이 필요했습니다. 그는 가능한 가장 단순한 것을 만들었습니다: 서버에 연결하고, GET /index.html을 보내고, HTML을 받고, 연결을 끊는 것이었죠. 헤더도 없고, 오류 코드도 없고, 이미지를 보내거나 무언가 잘못됐는지 알 방법도 없었습니다. 그냥 텍스트가 들어가고, 텍스트가 나오는 것뿐이었습니다.

이것이 HTTP/0.9였습니다—그게 문자 그대로 전부였기 때문에 "한 줄짜리 프로토콜"이라고도 불렸습니다. 요청 한 줄, 응답 한 스트림, 연결 종료.

한계는 명확했습니다: 리소스 하나하나마다 새 연결이 필요했습니다. 이미지 열 개가 있는 페이지는 열 번의 TCP 핸드셰이크를 의미했고—데이터가 흐르기 전에 각각 왕복 지연이 추가됐습니다. 하지만 작동했습니다. 개념을 증명했습니다. 웹이 존재하게 됐습니다.

HTTP/1.0: 헤더가 모든 것을 바꾸다

1996년이 되자, 사람들은 HTML 이상의 것을 전송하고 싶었습니다. 이미지도, 다양한 문서 형식도, 의미 있는 오류 메시지도 원했습니다. HTTP/1.0은 이를 가능하게 하는 장치를 추가했습니다: 바로 헤더입니다.

헤더는 메타데이터입니다. Content-Type: image/png는 브라우저에게 무엇을 받고 있는지 알려줍니다. User-Agent는 누가 요청하는지 식별합니다. 상태 코드—200 OK, 404 Not Found, 500 Internal Server Error—는 서버에게 무슨 일이 일어났는지 설명할 어휘를 제공했습니다.

HTTP/1.0은 또한 POST를 추가해 폼이 데이터를 전송할 수 있게 했고, HEAD를 추가해 파일을 다운로드하지 않고도 리소스가 존재하는지 확인할 수 있게 했습니다.

하지만 근본적인 문제는 그대로였습니다: 연결 하나에 요청 하나. 리소스가 서른 개인 페이지는 서른 번의 TCP 핸드셰이크를 의미했습니다. 프로토콜 자체가 병목이 된 것입니다.

HTTP/1.1: 연결을 끊지 않기

1997년에 출시된 HTTP/1.1에는 하나의 큰 아이디어가 있었습니다: 전화를 끊지 않는 것.

지속 연결—keep-alive라고도 불리는—은 브라우저가 여러 요청에 같은 TCP 연결을 재사용할 수 있게 했습니다. HTML을 요청하고 받은 다음, 같은 연결로 즉시 CSS를 요청하는 것입니다. 새 핸드셰이크 없이. 서버는 그냥... 다음 요청을 기다립니다.

이 단순한 변화가 지연 시간을 극적으로 줄였습니다. 하지만 새로운 문제가 생겼습니다: 헤드-오브-라인 블로킹입니다.

카페에서 한 줄로 서 있는 상황을 상상해보세요. 앞 사람이 복잡한 것을 주문합니다. 그냥 아메리카노만 원하는 사람도 모두 기다려야 합니다. HTTP/1.1도 마찬가지였습니다—요청이 한 번에 하나씩 순서대로 처리됐습니다. 느린 응답 하나가 뒤의 모든 것을 막았습니다.

브라우저는 이를 병렬로 여러 연결을 열어서 해결했습니다—보통 도메인당 여섯 개. 하지만 이것은 해결책이 아닌 임시방편이었습니다. 카페에서 계산대가 여섯 개면 하나보다 낫지만, 여전히 복잡한 주문 뒤에서 기다리는 건 마찬가지입니다.

HTTP/1.1은 또한 Host 헤더를 필수로 만들었는데, 이로써 가상 호스팅—하나의 IP 주소를 여러 웹사이트가 공유하는 것—이 가능해졌습니다. 이전에는 모든 웹사이트에 고유한 IP 주소가 필요했습니다. 이후에는 서버 하나가 어떤 도메인을 요청했는지 확인해서 수천 개의 도메인을 호스팅할 수 있게 됐습니다.

거의 20년 동안 HTTP/1.1이 인터넷을 지탱했습니다. 충분히 괜찮았죠. 그게 통하지 않을 때까지는요.

HTTP/2: 줄 서서 기다리지 않기

2015년에 표준화된 HTTP/2는 헤드-오브-라인 블로킹을 정면으로 공략했습니다.

핵심 통찰은 이것이었습니다: 왜 애초에 순서대로 요청을 처리해야 하는가? 큰 이미지를 기다리는 동안, 왜 작은 CSS 파일이 그 뒤에서 기다려야 하는가? HTTP/2는 멀티플렉싱을 도입했습니다—여러 요청과 응답이 하나의 연결에서 뒤섞여 준비되는 대로 전달되는 방식입니다.

이를 가능하게 하기 위해 HTTP/2는 텍스트에서 바이너리 프레이밍으로 전환했습니다. 메시지는 작은 프레임으로 분할되고, 스트림 식별자로 태그되어 자유롭게 뒤섞입니다. 브라우저는 도착 시 이를 재조립합니다. 전화 한 통으로 여러 대화를 나누는 것과 같습니다—각 문장에 어느 대화에 속하는지 태그가 붙어 있는 것처럼.

HPACK을 통한 헤더 압축은 낭비의 또 다른 원인을 줄였습니다. HTTP 헤더는 반복적입니다—같은 쿠키, 같은 사용자 에이전트, 같은 호스트, 요청마다. HPACK은 이전에 전송된 헤더 테이블을 유지하고 재전송 대신 인덱스로 참조합니다.

HTTP/2는 또한 서버 푸시를 도입했습니다: 서버가 index.html 바로 뒤에 style.css가 필요하다는 걸 안다면, 왜 요청을 기다리나요? 그냥 먼저 보내면 되죠. 실제로는 예상보다 제대로 하기 어려웠습니다—서버가 자주 잘못 예측했고—채택이 제한적이었습니다.

하지만 HTTP/2에는 해결할 수 없는 더 깊은 문제가 있었습니다. 멀티플렉싱은 HTTP 계층에서 일어났지만, 그 아래 계층에서는 여전히 모든 게 TCP 위에서 돌아가고 있었습니다. 그리고 TCP에는 자체적인 헤드-오브-라인 블로킹이 있습니다.

TCP 패킷이 손실되면, 프로토콜은 그 패킷이 재전송될 때까지 전체 연결을 멈춥니다. 모든 스트림, 모든 리소스, 모든 프레임—하나의 리소스에만 영향을 미칠 수 있는 패킷 하나를 기다리며 전부 멈추는 것입니다. HTTP/2는 식당에서 줄 서는 문제는 해결했지만, 모두가 여전히 같은 회전문에 갇혀 있었습니다.

HTTP/3: 문을 바꾸다

2022년 6월에 표준화된 HTTP/32은 과감한 일을 합니다: TCP를 완전히 버리는 것입니다.

대체제는 QUIC으로, UDP 기반으로 만들어진 전송 프로토콜이며 IETF에 의해 2021년 표준화됐습니다3. QUIC은 연결 단위가 아닌 스트림 단위로 신뢰성을 구현합니다. 한 스트림의 패킷이 손실되면, 그 스트림만 멈춥니다. 나머지는 계속 흐릅니다.

이것이 어느 계층에서도 헤드-오브-라인 블로킹이 없는 진정한 멀티플렉싱입니다. HTTP/2가 해결할 수 없었던 문제가 그냥... 사라진 것입니다.

QUIC은 또한 전송 핸드셰이크와 암호화 핸드셰이크를 결합합니다. 기존 HTTPS는 TCP 핸드셰이크, 그 다음 TLS 핸드셰이크가 필요했습니다—애플리케이션 데이터가 흐르기 전에 여러 번의 왕복이 필요했죠. QUIC은 둘을 동시에 처리하여 종종 단 한 번의 왕복으로 연결을 설정합니다. 재방문자의 경우 왕복 없이 연결을 재개할 수 있습니다.

QUIC은 UDP로 실행되기 때문에 애플리케이션 영역에서 자유롭게 발전할 수 있습니다. TCP는 운영 체제 커널에 내장돼 있습니다—변경하려면 인터넷의 모든 기기에 걸친 조율된 업데이트가 필요합니다. QUIC은 그냥 소프트웨어입니다. 업데이트가 수십 년이 아닌 몇 주 만에 배포됩니다.

QUIC은 또한 네트워크 변경을 우아하게 처리합니다. 휴대폰이 WiFi에서 셀룰러로 전환되면 TCP 연결이 끊깁니다—IP 주소가 바뀌었고, TCP는 IP로 연결을 식별하기 때문입니다. QUIC은 대신 연결 ID를 사용합니다. 연결이 원활하게 이전됩니다. 사용자는 알아채지 못합니다. 화상 통화가 끊기지 않습니다.

전환은 점진적이지만 꾸준히 이루어지고 있습니다. 2024년 말 기준, HTTP/3은 주요 브라우저의 95% 이상에서 지원되며 상위 1,000만 웹사이트의 약 3분의 1이 지원합니다4. 개선 효과는 조건이 가장 나쁜 곳에서 가장 중요합니다—패킷 손실이 많은 모바일 네트워크, 높은 지연 연결, 낭비되는 모든 밀리초가 체감되는 바로 그 상황에서.

패턴

각 버전은 의미의 하위 호환성을 유지했습니다—같은 메서드, 같은 헤더, 같은 시맨틱스. 변한 것은 와이어 포맷, 전송 방식, 비트를 여기서 저기로 더 빠르게 전달하는 메커니즘이었습니다.

버전연도주요 변경부딪힌 벽
HTTP/0.91991요청 하나, 연결 하나모든 리소스에 새 연결 필요
HTTP/1.01996헤더와 상태 코드여전히 연결당 요청 하나
HTTP/1.11997지속 연결요청이 줄 서서 기다림
HTTP/22015멀티플렉스 스트림패킷 손실 시 TCP가 모든 것을 차단
HTTP/32022QUIC이 TCP를 대체어느 계층에서도 차단 없음

빛의 속도는 변하지 않았습니다. 물리 법칙은 여전히 이깁니다. 하지만 HTTP는 물리 법칙이 허락하는 시간을 낭비하지 않는 법을 놀라울 만큼 영리하게 터득했습니다.

HTTP 버전에 대해 자주 묻는 질문

QUIC을 만드는 대신 TCP를 고치지 않은 이유는 무엇인가요?

TCP는 운영 체제 커널에 구현돼 있습니다. 변경하려면 수십억 개의 기기—휴대폰, 서버, 라우터, IoT 기기—에 걸친 조율된 업데이트가 필요하며, 그 중 많은 기기는 절대 업데이트되지 않을 것입니다. QUIC은 애플리케이션 코드로서 운영 체제 외부 영역에서 실행되므로 독립적으로 배포하고 업데이트할 수 있습니다. Google은 매주 QUIC 개선 사항을 배포했습니다; TCP 변경은 전파되는 데 수십 년이 걸립니다.

HTTP/3이 항상 HTTP/2보다 빠른가요?

신뢰할 수 있는 저지연 네트워크에서는 차이가 미미합니다. HTTP/3은 조건이 나쁠 때 진가를 발휘합니다—패킷 손실, 네트워크 전환, 높은 지연. 모바일 네트워크에서 가장 큰 개선을 볼 수 있습니다. 안정적인 광섬유 연결에서는 차이를 느끼지 못할 수도 있습니다.

HTTP/3을 위해 웹사이트를 업데이트해야 하나요?

아니요. HTTP/3은 애플리케이션 변경이 아닌 전송 계층의 변경입니다. HTML, CSS, JavaScript, API는 동일하게 작동합니다. 업그레이드는 서버와 CDN 수준에서 일어납니다. 호스팅 제공업체가 HTTP/3을 지원한다면, 방문자들은 자동으로 혜택을 받습니다.

HTTP/2는 왜 텍스트 대신 바이너리를 사용하나요?

텍스트 파싱은 느리고 모호합니다. 헤더는 어디서 끝나는가? 공백의 예외 상황은 어떻게 처리하는가? 바이너리 프레이밍은 명확하고 파싱이 빠릅니다. 단점은 디버깅이 어렵다는 것입니다—더 이상 눈으로 HTTP/2 트래픽을 읽을 수 없습니다. 하지만 성능 향상은 그만한 가치가 있었습니다.

HTTP/2 서버 푸시는 어떻게 됐나요?

좋은 아이디어였지만 실용적이지 않은 것으로 판명됐습니다. 서버는 클라이언트가 이미 캐시에 무엇을 가지고 있는지 안정적으로 예측할 수 없었고, 그래서 종종 버려질 리소스를 푸시했습니다. Chrome은 HTTP/2 세션의 단 0.05%만이 서버 푸시를 사용했다고 측정했습니다5. Chrome은 2022년 10월에 지원을 제거했고, Firefox는 2024년에 뒤따랐습니다. 권장 대안은 103 Early Hints로, 브라우저가 제안된 리소스를 가져올지 스스로 결정하게 합니다.

출처

이 페이지가 도움이 되었나요?

😔
🤨
😃