과거 HTTP 0.9는 오직 GET 메서드만을 지원하는 프로토콜이었습니다. 또한 Header 또한 존재하지 않았습니다. 이 프로토콜을 이용하여 전송할 수 있는 파일도 오직 HTML 파일만 전송이 가능했습니다.
HTTP 1.0
HTTP 1.0으로 넘어오게 되면서 header를 수정이 가능하게끔 되었고 상태 코드로 표현이 가능해졌으며 새로운 method들이 등장하게 되었습니다. 기존에도 GET, POST, PUT등의 메서드들이 정의되어 있었지만 HTTP/1.1로 넘어오게 되면서 더욱 명확히 정의되고 표준화가 되었습니다.
HTTP 1.0으로 프로토콜이 발전하게 되면서 HTTP를 이용하여 더 다양한 데이터를 전송이 가능하게 변경이 되었지만 HTTP를 이용하여 데이터를 전송하기 위해서는 많은 요청과 응답의 전송이 클라이언트와 서버간에 오고가야 한다는 단점이 존재했습니다.
HTTP를 통해서 데이터를 전송하기 위해서는 TCP 3 way hand shake를 이용하여 연결을 수립하는 단계가 필요했고 연결이 수립되고 HTTP Request가 전송되고 난 후 서버에서 Response가 클라이언트에 전달되게 되면 기존의 연결했던 TCP 연결을 해제 했어야 합니다.
당시 네트워크 대역폭과 서버 처리 능력이 오늘날보다 훨씬 낮았습니다. 따라서 효율성을 높이기 위해 연결을 짧게 유지하고 빠르게 해제하는 방식이 적합했습니다. 이러한 이유로 인해서 매 요청마다 연결을 수립하고 요청을 전송하고 응답을 받고 연결을 해제하는 작업이 모든 요청에서 이루어지다 보니 비효율적일 수 밖에 없었습니다.
HTTP 1.1
HTTP 1.1로 넘어오면서 기존의 HTTP 1.0이 갖던 많은 문제를 해결 했습니다. HTTP 1.1은 1997년에 등장하였지만 오늘날에도 활발하게 사용이 되고 있습니다. 이 이유는 새롭게 등장하게 된 기능들이 오늘날에도 유용하기 때문입니다. 이 기능들에 대해서 차례대로 다루어 보겠습니다.
HTTP 지속적 연결 상태
HTTP 지속적 연결 상태(HTTP persistent connection, 또는 HTTP keep-alive)는 단일 TCP 연결을 사용하여 여러 HTTP 요청/응답 쌍에 대해 새 연결을 여는 대신 여러 HTTP 요청/응답을 주고받는 개념입니다. HTTP 1.0 에서도 일부 클라이언트가 Connection : keep-alive 를 지원할 경우에는 지속적인 연결 상태를 유지할 수 있었습니다. 하지만 HTTP 1.0에서 Connection: keep-alive는 표준이 아니었고, 일관되게 동작하지 않는 경우도 있었습니다.
HTTP 1.1부터는 별도의 Connection: keep-alive 헤더 없이도 기본적으로 지속적 연결이 지원됩니다. 클라이언트나 서버가 연결을 종료하려면 명시적으로 Connection: close를 사용해야 하며, 타임아웃 설정을 통해 유휴 연결이 자동으로 종료될 수 있습니다. 이 조건은 HTTP 1.0 에서도 동일 했습니다.
대표적인 웹 서버인 Apach의 경우 약 5초 정도의 KeepAliveTimeout 짧은 타임아웃 시간을 이용하여 유휴 연결을 관리합니다. 짧은 타임아웃을 사용하는 이유는 타임아웃을 짧게 설정하면 여러 서버 프로세스나 스레드가 장시간 자원을 점유하는 문제를 방지하면서, 웹 페이지의 여러 구성 요소를 효율적으로 전달할 수 있다는 장점이 있기 때문입니다.
Pipelining
HTTP 파이프라이닝은 HTTP/1.1의 기능으로, 단일 TCP 연결을 통해 여러 HTTP 요청을 해당 응답을 기다리지 않고 전송할 수 있습니다.
HTTP/1.1은 서버가 파이프라이닝된 요청에 올바르게 응답해야 하며, 서버가 HTTP 파이프라이닝을 지원하지 않더라도 파이프라이닝되지는 않지만 유효한 응답을 제공해야 합니다. 이러한 요구 사항에도 불구하고 많은 기존 HTTP/1.1 서버가 올바른 파이프라이닝을 지원하지 않아 대부분의 HTTP 클라이언트가 HTTP 파이프라이닝을 사용하지 않을 수밖에 없습니다.
요청의 파이프라이닝은 지연 시간이 긴 연결에서 HTML 페이지 로딩 시간을 극적으로 개선하는 결과를 가져왔습니다. 하지만 여전히 서버는 요청을 받은 순서대로 응답을 보내야 하므로 전체 연결이 선입선출로 유지되고 HOL(Head-Of-line) blocking 가 발생할 수 있다는 단점을 갖고 있습니다.
청크 인코딩 Chunked transfer encoding
청크 인코딩을 지원한다는 것의 의미는 HTTP 1.1 버전에서 streaming 데이터를 전송이 가능하다는 것을 의미합니다. 청크 전송 인코딩에서 데이터 스트림은 겹치지 않는 일련의 청크로 나뉩니다. 청크는 서로 독립적으로 전송되고 수신됩니다. 현재 처리 중인 청크 외부의 데이터 스트림에 대한 지식은 송신자와 수신자 모두에게 언제든지 필요하지 않습니다.
HTTP 서버는 종종 압축을 사용하여 전송을 최적화합니다. 예를 들어, Content-Encoding: gzip 또는 Content-Encoding: deflate를 사용합니다. 압축과 청크 인코딩이 모두 활성화되면 콘텐츠 스트림이 먼저 압축된 다음 청크됩니다. 따라서 청크 인코딩 자체는 압축되지 않고 각 청크의 데이터는 개별적으로 압축됩니다. 그런 다음 원격 엔드포인트는 청크를 연결하고 결과를 압축 해제하여 스트림을 디코딩합니다.
스트림은 청크 단위로 잘게 나뉘어진 데이터가 들어오는 대로 순차적으로 처리하기 때문에 실시간성과 효율성을 극대화할 수 있습니다. 이러한 특징은 스트림 처리 패러다임은 수행할 수 있는 병렬 계산을 제한하여 병렬 소프트웨어와 하드웨어를 단순화하기 때문입니다.
병렬 계산을 제한하는 것이 단점처럼 보일 수 있지만, 이는 스트림 처리의 장점인 간결성과 실시간 처리 능력을 가능하게 만드는 중요한 요소입니다. 스트림 처리에는 데이터가 순서대로 처리되는 것이 중요한데 병렬처리를 과도하게 허용할 경우 데이터의 순서가 엉키거나 동기화 문제가 발생할 수 있기 때문입니다.
caching and conditional request
앞서 설명 했듯이 여러 헤더 속성을 사용가능하게 되면서 Cache-Control, E-Tag, Last-Modified, If-Modified-Since, If-None-Match 헤더 또한 사용이 가능하게 되었습니다.
HTTP 1.0에서는 기본적으로 Expires 헤더만을 사용해 리소스의 유효 기간을 정의했습니다. 하지만 HTTP 1/1에서는 E-Tag 및 Last-Modified 기반 캐싱 기능이 추가되었습니다. 이 기능으로 인해서 조건부 요청이 가능해졌습니다.
조건부 요청은 클라이언트가 특정 조건에 따라 리소스를 요청할 수 있도록 하는 기능입니다. 클라이언트가 서버에 특정 요청을 전송하였을 경우 서버는 클라이언트가 보낸 조건 E-Tag 또는 Last-Modified을 확인합니다. 리소스가 변경이 되지 않았다면 서버는 304 Not Modified 상태 코드를 응답하여 새로운 데이터를 전송하지 않고 캐시된 데이터를 사용하도록 합니다.
Domain Sharding
브라우저는 각 도메인의 활성 연결 수를 제한합니다. 해당 제한을 초과하는 리소스를 동시에 다운로드할 수 있도록 도메인 샤딩(Domain sharding)은 콘텐츠를 여러 하위 도메인으로 분할합니다. 이러한 하위 도메인들 마다 별도의 연결을 생성해야 합니다. 여러 도메인을 사용하여 여러 리소스를 제공하는 경우, 브라우저는 더 많은 리소스를 동시에 다운로드할 수 있으므로, 페이지 로드 시간이 빨라지고 사용자 경험이 향상됩니다.
HTTP 요청의 초기 응답은 일반적으로 다운로드 해야 하는 JavaScript, CSS, 이미지 및 기타 미디어 파일과 같은 기타 리소스를 나열하는 HTML 파일입니다. 브라우저는 도메인 당 활성 연결 수를 제한하므로, 리소스를 순차적으로 다운로드해야 해서 단일 도메인에서 필요한 모든 리소스를 제공하는 데 속도가 느려질 수 있습니다. 도메인 샤딩을 사용하면 필요한 다운로드가 둘 이상의 도메인에서 제공되므로, 브라우저가 필요한 리소스를 동시에 다운로드할 수 있습니다.
HOL(Head-Of-line) Blocking
위의 그림을 통해서 HOL Blocking이 어떤 문제인지 알아보겠습니다. 위 그림의 Input들은 대기열을 큐로 관리하여 입력된 요청들을 순차적으로 처리합니다. 이때 위의 그림에서 1번과 3번은 서로 동일한 출력 인터페이스로 패킷을 전송해야 하는 경쟁 상황임을 알 수 있습니다. 이 경우 Switching Fabric이 이러한 상황을 해결하기 위하여 3번 Input을 패킷을 전송하기로 결정할 경우 1번 Input은 작업을 처리할 수 없게 됩니다.
1번 Input의 경우 헤드에 있는 데이터가 처리되지 못하고 막혀 있기 때문에, 뒤쪽 데이터도 처리되지 못합니다. 만약 3번 Input의 작업이 처리되었다고 하더라도 2번 Input에 있는 4번 요청를 처리한다고 1번 Input의 작업이 또 연기될 수 있는 가능성이 존재합니다.
이러한 문제가 발생한 이유는 스위치 패브릭이 한 번에 하나의 입력에서 하나의 출력으로만 데이터가 이동이 가능하다는 동작의 제한 때문입니다. 또한 입력 포트의 큐는 패킷 순서를 유지하기 위해 FIFO로 동작합니다. 그렇기 때문에 두 개 이상의 입력이 동일한 출력 포트로 데이터를 보내려고 할 때 충돌이 발생하게 되는 것입니다.
HTTP 2
Multiplexing
Multiplexing(멀티플렉싱)은 단일 TCP 연결에서 여러 데이터 스트림을 병렬로 처리할 수 있도록 설계된 기술입니다. 예를 들어 여러 전화 통화를 하나의 물리적 회선에서 동시에 처리할 수 있도록 설계하는 방법을 의미합니다.
도메인 샤딩은 HTTP/1.1에서 HOL 블로킹 문제를 우회하기 위해 사용된 기법입니다. 이는 웹 브라우저가 병렬로 더 많은 요청을 처리할 수 있도록 여러 도메인에 리소스를 분산하는 방식입니다. 그러나 멀티플렉싱이 도입되면서 도메인 샤딩은 비효율적이며 불필요해졌습니다.
HTTP/2의 멀티플렉싱은 단일 TCP 연결을 통해 다수의 요청과 응답을 스트림 단위로 병렬 처리합니다. 각 스트림은 독립적이므로, 특정 스트림의 지연이 다른 스트림에 영향을 미치지 않습니다. 또한, 스트림은 요청의 중요도에 따라 우선순위와 가중치를 설정할 수 있으며, 서버는 이를 기반으로 동적으로 대역폭을 분배합니다.
스트림은 순수와 상관 없이 병렬로 전송이 됩니다. 이 때 전송되는 모두 고유한 Stream ID를 소유하고 있습니다. 수신 측은 각 프레임의 Stream ID를 확인하여 해당 프로엠이 어떤 스트림에 속하는지 식별하여 섞여 있는 데이터를 원래의 요청이나 응답 데이터로 다시 조합할 수 있습니다.
멀티플렉싱을 통해 HTTP/2는 네트워크 대역폭을 더욱 효율적으로 사용하며, 요청/응답 처리 속도를 최적화합니다. 결과적으로 HOL 블로킹 문제를 해결하고, 페이지 로드 시간을 단축하며, 사용자 경험을 향상시킵니다.
Binary Framing Layer
HTTP/1.1 에서 body 부분이 text로 전송이 되었던것과 달리 HTTP/2에서 부터는 binary frame 단위로 전송이 이루어집니다. 기존의 HTTP/1.1 에서는 header와 body가 CRLF(\r\n)를 기준으로 구분이 되었지만 HTTP/2에서 부터는 헤더와 바디를 binary frame으로 나누고 이 frame을 layer로 구분하고 있어 이를 binary framing layer라고 부르는 것입니다.
기존의 문자열 기반으로 전송이 될 경우에는 추가적인 파싱과정과 대소문자, 공백, 줄바꿈 등 다양한 형식에 영향을 받는다는 제약사항이 있었습니다. 하지만 binary 데이터의 경우 binary protocol이 엄격하게 정의되어 있어 해석과 처리가 더 신뢰성 있게 이루어집니다.
또한 binary의 경우 HPACK 헤더 압축과 같은 최적화 기법을 사용하여 데이터를 최적화하기에 적합하다는 특징을 갖습니다. 또한 기존의 HTTP/1.1에서는 데이터 처리 중 많은 데이터를 바이너리로 변환 했어야 했지만 HTTP/2는 처음부터 바이너리로 처리하기 때문에 변환 과정이 필요 없다는 장점을 갖고 있습니다.
Server Push
기존 HTTP/1.1에서는 모든 응답이 클라이언트의 요청이 있어야만 가능했습니다. 하지만 HTTP/2에서는 Server Push 기능이 도입되어, 클라이언트가 명시적으로 요청하지 않은 리소스도 서버가 필요하다고 판단하면 클라이언트에 미리 전송할 수 있게 되었습니다.
예를 들어, 클라이언트가 HTML 파일을 요청했을 때 서버는 해당 HTML 파일을 응답하면서, HTML에 포함된 CSS, JavaScript 등 중요한 리소스를 추가 요청 없이 미리 푸시할 수 있습니다. 이로 인해 클라이언트가 HTML을 분석하고 나서 추가 요청을 보낼 필요가 없어, 페이지 로드 시간이 단축됩니다.
Server Push의 동작 방식은 다음과 같습니다:
클라이언트가 초기 요청을 보냅니다. (예: index.html)
서버는 index.html 파일을 응답하면서, 서버에서 설정한 추가로 필요한 리소스(CSS, JS 등)를 푸시합니다.
클라이언트는 푸시된 리소스를 수신하여 요청 없이도 필요한 데이터를 받을 수 있습니다.
이 기능은 HTTP/2의 멀티플렉싱을 활용하여, 하나의 연결에서 여러 리소스를 병렬로 전송하기 때문에 네트워크 효율성을 높입니다. 다만, 클라이언트가 이미 해당 리소스를 캐싱하고 있는 경우 불필요한 데이터 전송이 발생할 수 있으며, 이를 방지하기 위해 클라이언트와 서버 간에 캐싱 상태를 동기화하는 추가적인 메커니즘이 사용될 수 있습니다.
Server Push의 한계는 클라이언트가 이미 캐시에 리소스를 보유하고 있을 경우를 구분하지 못한다는 것입니다. 서버가 동일한 리소스를 푸시하면 불필요한 데이터 전송이 발생합니다. 이로인해 클라이언트가 필요 없는 데이터를 수신하여 리소스 낭비가 발생할 수 있습니다.
또한 서버 푸시는 서버 쪽에서 어떤 리소스를 푸시해야 하는지 결정해야 하므로, 서버 설정 및 구현이 복잡해질 수 있습니다. 특히 동적 콘텐츠를 생성하는 서버에서는 HTML에 포함된 리소스를 동적으로 추출하고 적절히 푸시하는 로직을 추가해야한다는 단점을 갖고 있습니다.
그래서 Server Push의 경우 HTTP/3에서 클라이언트 중심의 리소스 요청 방식을 지원하게 됨으로써 더이상 사용이 되지 않을 추세로 보입니다.
HTTP/2의 한계
오늘날 네트워크를 사용하여 데이터를 연결하는 디바이스는 과거에 비해 더욱 다양해졌습니다. HTTP/2는 이런 여러 디바이스에서 완벽히 적용하기에는 제약사항이 있었습니다. 또한 HTTP/1.1에서의 HOL 블로킹의 문제를 멀티 플렉싱으로 해결 헀지만 TCP 계층에서의 HOL 블로킹은 해결하지 못한다는 한계가 있었습니다.
특징
HTTP/1.1의 HOL 블로킹
TCP 계층의 HOL 블로킹 (HTTP/2)
발생 계층
애플리케이션 계층 (HTTP 프로토콜 설계)
전송 계층 (TCP 프로토콜 설계)
원인
하나의 TCP 연결에서 요청이 순차적으로 처리됨
패킷 손실 시 순서 보장을 위한 재전송 메커니즘
영향 범위
하나의 TCP 연결에 국한
HTTP/2의 모든 스트림에 영향을 미침
해결 방법
멀티플렉싱(HTTP/2), 다중 연결(HTTP/1.1의 도메인 샤딩)
QUIC 프로토콜 기반의 HTTP/3
주로 영향을 받는 환경
대량의 요청이 필요한 복잡한 웹 애플리케이션
패킷 손실이 잦은 모바일 네트워크 환경
HTTP/2는 단일 TCP 연결을 하기 때문에 전송하던 패킷이 손실되었을 경우 단일 연결에서 모든 스트림이 패킷 손실의 영향을 받는다는 문제가 생깁니다. 이러한 문제는 패킷 손실률이 높은 모바일 환경에서 특히 문제가 되는 사항이었습니다.
또한 모바일에서는 Wi-FI와 LTE/5G 네트워크 간 전환이 빈번합니다. HTTP/2의 단일 TCP 연결은 네트워크 전환 시 연결이 끊기면 모든 스트림이 중단되며, 이를 복구하는 데 추가적인 지연이 발생합니다.
HTTP/3
QUIC은 기존의 HTTP/2의 경우 TCP 기반의 multiplexing을 구현했다면 QUIC은 UDP을 기반으로 multiplexing 을 구현했다는 특징을 갖습니다.
QUIC은 TCP + TLS + HTTP/2를 합친것과 유사합니다.
연결 설정 지연 시간
향상된 혼잡 제어
헤드 오브 라인 차단 없이 멀티플렉싱 가능
전방 오류 수정
연결 마이그레이션
QUICK connection ID
TCP와 달리 QUIC은 UDP 기반으로 동작하기 때문에 송신자와 수신자를 식별하기 위한 용도로 Connection ID를 사용합니다. 각 연결마다 고유한 Connection ID가 생성되며, 이는 QUIC 프로토콜에서 지속적으로 유지됩니다.
QUIC은 연결을 IP 주소나 포트 번호로 식별하지 않고 Connection ID를 통해 연결을 식별합니다. 이러한 특징으로 인해서 모바일 기기가 네트워크(Wi-Fi, LTE 등)을 전환하면 IP 주소와 포트가 변하더라도 Connection ID을 통해 동일한 연결임을 인식할 수 있습니다.
하지만 보안을 위해 네트워크 식별 정보를 보호하기 위해 Connection ID를 변경할 수 있는 메커니즘을 제공합니다. 클라이언트와 서버는 QUIC 핸드셰이크 과정에서 Connection ID를 교환하여 연결을 식별합니다.
QUIC Handshake
연결 설정에 대한 완전한 설명은 QUIC Crypto 설계 문서를 참조하십시오. 간단히 말해, QUIC 핸드셰이크는 페이로드를 전송하기 전에 0회 왕복(RTT)이 필요한 경우가 빈번하며, 이는 TCP+TLS의 1~3회 왕복과 비교됩니다.
QUIC 클라이언트가 서버에 처음 연결할 때, 클라이언트는 핸드셰이크를 완료하기 위해 필요한 정보를 얻기 위해 1회 왕복 핸드셰이크를 수행해야 합니다. 클라이언트는 불완전한(비어 있는) 클라이언트 헬로(CHLO)를 보내고, 서버는 클라이언트가 진행하기 위해 필요한 정보(예: 소스 주소 토큰 및 서버 인증서)를 포함한 거부(REJ)를 보냅니다. 클라이언트가 다음 번에 CHLO를 보낼 때는 이전 연결에서 캐시된 자격 증명을 사용하여 즉시 암호화된 요청을 서버로 보낼 수 있습니다.
QUIC Crypto
기존의 HTTP/2의 경우 HTTPS의 사용이 강제되지 않았습니다. 그렇기 때문에 HTTP/2와 함께 TLS 를 사용함으로써 보안성을 높일 수 있었지만 HTTP/2의 작업에서 추가적인 보안작업이 수행되고 HTTP/2는 구현의 복잡성이 높아 레이턴시를 낮추는 문제가 있었습니다.
QUIC은 CRYPTO 프레임을 사용해 암호화 핸드셰이크 데이터를 전송하며, 이는 QUIC 자체의 패킷 보호 메커니즘에 의해 보호됩니다. 전송 계층(TCP)과 암호화 계층(TLS)이 분리된 HTTP/2 + TLS보다 더 빠르고 간결합니다.
QUIC은 암호화 데이터를 전송할 때도 순서 보장이 필요 없는 UDP 기반으로 작동합니다. TCP 기반의 HTTP/2는 패킷 손실 시 순서 보장을 위해 추가적인 재전송이 필요하지만, QUIC은 재전송 없이도 연결 지연을 최소화합니다.
연결 설정 중 주소 검증
연결 설정은 양쪽 끝점(endpoints)에 대해 암묵적으로 주소 검증을 제공합니다. 특히, Handshake 키로 보호된 패킷을 수신하면 클라이언트가 서버로부터 Initial 패킷을 수신했음을 확인할 수 있습니다. 서버가 클라이언트로부터 Handshake 패킷을 성공적으로 처리하면, 해당 클라이언트 주소가 검증되었다고 간주할 수 있습니다.
패킷 손실, 특히 서버의 Handshake 패킷 손실은 서버가 클라이언트가 데이터를 전송하지 않을 때 전송하지 못하고 증폭 제한에 도달하는 상황을 초래할 수 있습니다. 이로 인해 핸드셰이크 교착상태(deadlock)가 발생하지 않도록, 클라이언트는 암호 재전송 타임아웃(crypto retransmission timeout)이 발생할 때 패킷을 전송해야 합니다(SHOULD). 클라이언트가 재전송할 데이터가 없고 Handshake 키를 가지고 있지 않다면, Initial 패킷을 최소 1200 바이트 크기의 UDP 데이터그램으로 전송해야 합니다(SHOULD). 클라이언트가 Handshake 키를 가지고 있다면, Handshake 패킷을 전송해야 합니다(SHOULD).
서버는 암호화 핸드셰이크를 시작하기 전에 클라이언트 주소를 검증하고자 할 수 있습니다. QUIC은 Initial 패킷 내의 토큰을 사용하여 핸드셰이크 완료 전에 주소 검증을 제공합니다. 이 토큰은 Retry 패킷(8.1.1절 참고)을 통해 연결 설정 중에 클라이언트에 전달되거나, 이전 연결에서 NEW_TOKEN 프레임(8.1.2절 참고)을 통해 제공됩니다.
주소 검증이 이루어지기 전 서버가 전송할 수 있는 데이터 양에 대한 제한 외에도, 서버는 혼잡 제어기(congestion controller)에 의해 설정된 제한에 의해 제약을 받습니다. 클라이언트는 혼잡 제어기에 의해서만 제약받습니다.
질문
Q : HTTP/1.0과 HTTP/1.1의 주요 차이점은 무엇인가요?
키워드 : 지속적 연결(Persistent Connection), 추가 메서드(HEAD, POST), 상태 코드 도입, 캐싱 메커니즘의 개선 등
HTTP 헤더를 이용하여 지속적 연결을 기본적으로 지원한다는 차이가 있습니다. 또한 기존에는 HTTP 메서드 중 GET만 지원하였지만 HTTP/1.1로 넘어오면서 메서드들의 정의가 더욱 명확해지고 헤더에 더 많은 정보를 담을 수 있게 되었습니다. 상태코드를 이용하여 응답 결과를 반환이 가능해지고 Cache-Control 를 헤더에 추가하여 캐싱 및 조건부 요청이 가능해졌습니다.
Q : HTTP 지속적 연결 상태(Keep-Alive)의 개념과 HTTP/1.1에서의 기본 동작 방식을 설명해주세요.
키워드 : 단일 TCP 연결에서 여러 요청/응답을 주고받는 방식, Connection: close 헤더의 사용, 유휴 연결의 타임아웃 관리 등
기본적으로 지속적 연결 상태는 헤더에 Connection : close가 명시적으로 표기되기 이전까지 연결을 유지합니다. 지속적 연결 상태는 서버에서 명시적으로 연결을 종료하지 않는 이상 단일 TCP 연결을 유지한 상태로 요청과 응답을 주고 받는 방식을 사용합니다.
Q : HTTP/1.1에서 청크 인코딩(Chunked Transfer Encoding)의 역할과 이를 사용하는 이유는 무엇인가요?
키워드 : 스트리밍 데이터 전송, 데이터 스트림을 청크 단위로 나누어 전송하는 방식, 실시간성과 효율성 증대
기존 HTTP/1에서는 HTTP로 전송이 가능한 데이터 단위는 문자열이었습니다. 청크 인코딩이 HTTP/1.1에 등장하게 됨으로써 스트림을 사용이 가능하게 되었습니다. 스트림의 사용이 가능한 이유는 전송하는 데이터가 충분히 작아졌기 때문입니다. 청크는 데이터를 gzip과 같은 포맷으로 압축하는데 이 데이터는 독립적인 단위를 보장하기 때문에 서로 중복되지 않고 스트림에 전송될 수 있을 만큼 충분히 작은 크기로 인코딩 됩니다. 데이터가 청크 단위로 잘게 나뉘어지면 스트림은 이 데이터를 순차적으로 처리하기 때문에 실시간성과 효율성을 극대화 할 수 있다는 장점이 있습니다.
Q : HTTP/1.1에서 캐싱 메커니즘이 어떻게 발전했는지, 특히 E-Tag와 Last-Modified 헤더의 역할을 설명해주세요.
키워드 : 조건부 요청, 304 Not Modified 응답, 캐시 효율성 향상
HTTP 1.0에서는 기본적으로 Expires 헤더만을 사용해 리소스의 유효 기간을 정의했습니다. 하지만 HTTP 1/1에서는 E-Tag 및 Last-Modified 기반 캐싱 기능이 추가되었습니다. 이 기능으로 인해서 조건부 요청이 가능해졌습니다.
조건부 요청은 클라이언트가 특정 조건에 따라 리소스를 요청할 수 있도록 하는 기능입니다. 클라이언트가 서버에 특정 요청을 전송하였을 경우 서버는 클라이언트가 보낸 조건 E-Tag 또는 Last-Modified을 확인합니다. 리소스가 변경이 되지 않았다면 서버는 304 Not Modified 상태 코드를 응답하여 새로운 데이터를 전송하지 않고 캐시된 데이터를 사용하도록 합니다.
Q : HTTP 파이프라이닝이 무엇이며, 이로 인해 발생할 수 있는 Head-of-Line (HOL) Blocking 문제에 대해 설명해주세요
키워드 : 단일 TCP 연결에서 여러 요청을 순차적으로 보내는 방식, HOL Blocking의 원인과 영향
HTTP 파이프라이닝은 클라이언트가 단일 TCP 연결을 통해 여러 HTTP 요청을 순차적으로 전송하여 네트워크 효율성을 높이는 기술로, 주로 HTTP/1.1에서 사용됩니다. 그러나 이 방식은 Head-of-Line (HOL) Blocking 문제를 야기합니다. 데이터 전송이 지연되거나 실패할 경우 그 뒤에 이어지는 모든 요청들이 대기 상태에 머무르게 되어 전체적인 응답 시간이 길어지고 사용자 경험이 저하됩니다. 이러한 문제가 발생하는 원인은 순차적 응답 처리와 네트워크 지연, 서버의 처리 지연등이 있습니다.
Q: HTTP/2의 Server Push 기능이 무엇이며, 이 기능이 HTTP/3에서는 왜 덜 사용되는지 설명해주세요.
키워드 : 클라이언트 요청 없이 서버가 리소스를 푸시하는 방식, 캐싱 상태의 불일치 문제, HTTP/3에서의 클라이언트 중심 요청 방식
Server Push는 클라이언트가 요청하지 않더라도 서버에서 일방적으로 데이터를 전송할 수 있는 기능을 이야기 합니다. 이 기능이 유용한 이유는 예를 들어 HTML을 클라이언트에 요청 헀을 경우 HTML을 파싱하는 과정에서 중요한 파일들 css 와 js 파일들을 클라이언트가 추가적인 요청을 하지 않더라도 전송이 가능하여 네트워크 요청을 줄일 수 있다는 장점이 있습니다.
하지만 Server Push는 브라우저에서 캐싱되어 있는 데이터를 재 사용이 불가능하다는 단점이 있습니다. 또한 서버 푸시는 서버 쪽에서 어떤 리소스를 푸시해야 하는지 결정해야 하므로, 서버 설정 및 구현이 복잡해질 수 있습니다. 특히 동적 콘텐츠를 생성하는 서버에서는 HTML에 포함된 리소스를 동적으로 추출하고 적절히 푸시하는 로직을 추가해야한다는 단점을 갖고 있습니다.
Q : HTTP/2의 멀티플렉싱(Multiplexing)이 HTTP/1.1의 HOL Blocking 문제를 어떻게 해결하는지 설명해주세요.
키워드 : 단일 TCP 연결에서 여러 스트림을 병렬로 처리, 특정 스트림의 지연이 다른 스트림에 영향을 미치지 않음
HTTP/1.1에서는 단일 TCP 연결을 통해 요청과 응답이 순차적으로 처리되기 때문에, 하나의 요청이 지연되면 그 뒤에 있는 모든 요청도 지연되는 Head-of-Line (HOL) Blocking 문제가 발생했습니다. 이를 해결하기 위해 HTTP/2는 멀티플렉싱 기능을 도입하였습니다.
HTTP/2의 멀티플렉싱은 단일 TCP 연결 내에서 여러 개의 스트림을 동시에 처리할 수 있도록 합니다. 각 스트림은 고유한 Stream ID를 가지며, 요청과 응답이 작은 프레임 단위로 나누어 전송됩니다. 이러한 프레임들은 서로 다른 스트림 간에 인터리빙되어 동시에 전송될 수 있어, 특정 스트림의 지연이 다른 스트림에 영향을 미치지 않게 됩니다.
또한, HTTP/2는 스트림의 우선순위를 설정할 수 있어 중요한 요청이 먼저 처리되도록 조정할 수 있습니다. 이러한 메커니즘을 통해 HTTP/2는 애플리케이션 계층에서 발생하던 HOL Blocking 문제를 효과적으로 완화시켰습니다.
Q : HTTP/2에서 겪었던 HOL Blocking 문제는 HTTP/1.1과 어떤 차이가 있었고 HTTP/3이 이 문제를 어떻게 개선하고자 했는지 설명해주세요
HTTP/2는 멀티플렉싱을 도입하여 단일 TCP 연결 내에서 여러 스트림을 병렬로 처리함으로써 애플리케이션 계층에서의 HOL Blocking 문제를 완화했습니다. 그러나 TCP 자체의 전송 계층에서도 여전히 HOL Blocking이 존재하여, 패킷 손실 시 전체 스트림이 영향을 받는 한계가 있었습니다.
이를 해결하기 위해 HTTP/3은 QUIC 프로토콜을 채택하여 UDP 기반의 멀티플렉싱을 구현함으로써 전송 계층에서의 HOL Blocking 문제를 완전히 제거했습니다. QUIC은 개별 스트림이 독립적으로 전송되기 때문에 한 스트림의 지연이나 패킷 손실이 다른 스트림에 영향을 미치지 않으며, 이를 통해 전반적인 네트워크 성능과 안정성을 크게 향상시켰습니다.
Q : QUIC 프로토콜이 HTTP/2의 TCP 기반 멀티플렉싱에서 가지는 주요 이점과, 이를 통해 HTTP/3이 어떻게 성능을 향상시키는지 설명해주세요.
TCP는 패킷 손실 시 전체 연결에 영향을 미쳐 모든 스트림이 지연되는 반면, QUIC은 UDP를 기반으로 하여 각 스트림이 독립적으로 전송되고 관리됩니다. 이로 인해 하나의 스트림에서 패킷이 손실되더라도 다른 스트림에는 영향을 미치지 않아 HOL Blocking을 방지할 수 있습니다.
또한, QUIC은 0 RTT 핸드셰이크를 지원하여 연결 설정 지연 시간을 크게 줄였으며, 내장된 암호화 기능을 통해 보안성을 강화했습니다. 이러한 이점들을 통해 HTTP/3은 더 낮은 지연 시간과 높은 데이터 전송 효율성을 제공하며, 특히 네트워크 환경이 불안정한 상황에서도 안정적인 성능을 유지할 수 있게 되었습니다.
Q: QUIC이 모바일 네트워크 환경에서 어떻게 연결 마이그레이션을 지원하는지 설명해주세요.
QUIC 프로토콜은 모바일 네트워크 환경에서 발생할 수 있는 IP 주소나 포트 번호의 변경에도 불구하고 연결을 지속할 수 있는 연결 마이그레이션 기능을 지원합니다. 이는 각 QUIC 연결에 고유한 Connection ID를 할당하여, 클라이언트가 네트워크를 전환할 때 새로운 IP 주소나 포트 번호로 변경되더라도 동일한 Connection ID를 유지함으로써 기존 연결을 이어갈 수 있게 합니다.
이러한 메커니즘 덕분에 사용자가 Wi-Fi에서 LTE로, 또는 그 반대로 네트워크를 전환할 때도 중단 없이 데이터 전송이 가능하며, 재연결 과정에서 발생할 수 있는 지연이나 패킷 손실을 최소화할 수 있습니다. 결과적으로 QUIC의 연결 마이그레이션 기능은 모바일 사용자의 원활한 인터넷 경험을 보장하며, 네트워크 전환 시에도 높은 성능과 안정성을 유지할 수 있도록 합니다.