HTTP/1.x에서의 연결 관리
HTTP에서 연결 관리는 웹사이트와 웹 애플리케이션의 성능에 큰 영향을 주는 중요한 주제다.
HTTP/1.x에는 단기 연결, 지속적 연결, HTTP 파이프라이닝 등 여러 모델이 있다.
HTTP는 주로 TCP를 전송 프로토콜로 사용하며, 클라이언트와 서버 간의 연결을 제공한다.
HTTP 초기에는 이러한 연결을 처리하기 위해 단일 모델을 사용했다.
이러한 연결은 수명이 짧아, 요청을 보낼 때마다 새로운 연결이 만들어지고 답변을 받으면 연결이 끊어졌다.
이 간단한 모델은 성능에 대한 선천적인 한계를 가지고 있었다.
각 TCP 연결을 여는 것은 많은 리소스를 소모하는 작업이다.
클라이언트와 서버 간에는 여러 메시지를 교환해야 한다.
네트워크 지연 시간과 대역폭은 요청을 보내야 할 때, 성능에 영향을 준다.
현대의 웹 페이지는 많은 정보를 제공하기 위해 많은 요청(12개 이상)이 필요하므로 이 초기 모델은 비효율적이다.
HTTP/1.1에서 두 가지 새로운 모델이 만들어졌다.
지속적 연결 모델은 연속적인 요청 사이에 연결을 열어두어 새 연결을 여는 데 필요한 시간을 줄인다.
HTTP 파이프라이닝 모델은 한 단계 더 나아가서 답변을 기다리지 않고도 여러 연속적인 요청을 보내서 네트워크의 지연 시간을 크게 줄인다.
참고 : HTTP/2는 연결 관리를 위한 추가 모델을 추가한다.
HTTP의 연결 관리가 두 개의 연속된 노드 간의 연결(end-to-end가 아닌 hop-by-hop 연결)에 적용된다는 점에 유의하는 것이 중요하다.
클라이언트와 첫 번째 프록시 간의 연결에 사용되는 모델은 프록시와 대상 서버(또는 중간 프록시) 간의 모델과 다를 수 있다.
Connection 및 Keep-Alive와 같은 연결 모델을 정의하는 데 관련된 HTTP 헤더는 hop-by-bop 헤더이며, 값은 중간 노드에서 변경할 수 있다.
관련 주제는 HTTP 연결 업그레이드 개념으로 HTTP/1.1 연결이 TLS/1.0, WebSocket 또는 일반 텍스트의 HTTP/2와 같은 다른 프로토콜로 업그레이드 된다.
이 프로토콜 업그레이드 메커니즘은 다른 곳에 더 자세히 설명되어 있다.
단기 연결 Short-lived connections
HTTP의 원래 모델이자 HTTP/1.0의 기본 모델은 단기 연결이다.
각 HTTP 요청은 자체 연결에서 완료된다.
이것은 각 HTTP 요청 전에 TCP 핸드셰이크가 발생하고 직렬화됨을 의미한다.
TCP 핸드셰이크 자체에는 시간이 많이 걸리지만, TCP 연결은 부하(TCP 연결이 처리해야 하는 데이터 전송량이나 그로 인해 발생하는 네트워크의 작업량)에 적응하여 지속적인(또는 warm) 연결이 많을수록 효율성이 높아진다.
TCP 핸드셰이크는 연결을 설정하는 과정이며, 이 과정은 시간이 걸린다.
하지만 TCP 연결이 한 번 설정된 후, 그 연결이 계속 유지되면서 데이터를 주고받게 되면, TCP 연결이 점차 그 작업에 적응한다.
지속적인 연결을 유지할수록 TCP는 네트워크 상태에 맞춰 더 효율적으로 데이터를 전송할 수 있게 된다.
따라서, 매번 새로운 연결을 만드는 것보다는 연결을 유지하면서 데이터를 주고받는 것이 더 효율적이다.
TCP 연결은 데이터를 주고받는 과정에서 네트워크의 상태와 전송량에 따라 전송 속도나 효율성을 조정하는 특성이 있다.
즉, 연결이 계속되면서 데이터 전송이 많아질수록 TCP 연결은 점점 더 효율적으로 동작하도록 조정된다.
부하(load)라는 단어는 TCP 연결을 통해 전송되는 데이터의 양이나 그로인한 네트워크의 작업량을 의미한다.
쉽게 말해, 부하는 TCP 연결이 처리해야 하는 데이터 전송량이나 그로 인해 발생하는 네트워크의 부담을 뜻한다.
"TCP connection adapts to its load(TCP 연결은 부하에 적응한다.)"는 이러한 데이터 전송량에 맞게 조정한다는 의미이다.
단기 연결은 TCP의 이러한 효율성 기능을 활용하지 못하며, 새로운 cold 연결을 통해 지속적으로 전송함으로써 성능이 최적인 상태보다 낮다.
짧은 연결은 TCP가 제공하는 효율적인 기능을 제대로 사용하지 못한다.
매번 새로운 연결을 만들다 보니, 데이터 전송 속도가 느려지거나 성능이 떨어지게 된다.
쉽게 말해, 짧은 연결은 빠르고 효율적인 전송을 방해할 수 있다.
이 모델은 HTTP/1.0에서 사용되는 기본 모델이다.(Connection 헤더가 없거나 값이 close로 설정된 경우다.)
HTTP/1.1에서 이 모델은 Connection 헤더가 close 값으로 전송될 때만 사용한다.
참고 : 지속적인 연결을 지원하지 않는 매우 오래된 시스템을 사용하는 경우가 아니면 이 모델을 사용할 만한 강력한 이유는 없다.
지속적인 연결 Persistent connections
단기 연결에는 두 가지 큰 걸림돌이 있다.
새 연결을 설정하는 데 상당한 시간이 걸리고, 기본 TCP 연결의 성능은 이 연결이 일정 시간 동안 사용중일 때만 향상된다.(warm 연결)
단기 연결은 일정 시간 동안 지속적으로 연결을 유지하지 못하여 성능 향상을 기대할 수 없다.
이러한 문제를 완화하기 위해 HTTP/1.1 이전에도 지속 연결이라는 개념이 설계되었다.
또는 이를 keep-alive 연결이라고 부를 수도 있다.
지속 연결은 일정 시간 동안 열려 있는 연결이며 여러 요청에 재사용될 수 있어, 새 TCP 핸드셰이크가 필요 없고 TCP의 성능 향상 기능을 활용할 수 있다.
이 연결은 영원히 열려 있지 않는다.
일정 시간이 지나면 프로세스가 실행하고 있지 않은 상태의 연결은 닫힌다.(서버는 keep-alive 헤더를 사용하여 연결이 열려 있어야 하는 최소 시간을 지정할 수 있다.)
지속적인 연결에도 단점이 있다.
프로세스가 실행하고 있지 않은 상태일 때에도 서버 리소스를 소모하고 부하가 많을 때는 Dos 공격을 수행할 수 있다.이런 경우, 프로세스가 실행하고 있지 않은 상태가 되자마자 닫히는 비지속형 연결을 사용하면 더 나은 성능을 제공할 수 있다.
HTTP/1.0 연결은 기본적으로 지속적이지 않다.
Connection을 close가 아닌 다른 것으로 설정(보통 retry-after헤더)하면, 연결이 영구적으로 유지된다.
HTTP/1.1에서는 지속성이 기본값이며 헤더는 더 이상 필요하지 않다.(하지만 HTTP/1.0으로 대체가 필요한 경우엔 대비하는 방어책으로 관련 헤더가 추가된다.)
HTTP 파이프라이닝 HTTP pipelining
참고 : HTTP 파이프라이닝은 현대 브라우저에서는 기본적으로 활성화되어 있지 않다.
버그가 있는 프록시는 여전히 흔하며, 이는 웹 개발자가 쉽게 예측하거나 진단할 수 없는 이상하고 불규칙한 동작을 유발한다.
파이프라이닝을 올바르게 구현하는 것은 복잡하다.
전송 중인 리소스의 크기, 사용될 유효한 RTT(왕복 시간), 그리고 유효 대역폭은 파이프라인에 의해 제공되는 개선에 직접적인 영향을 미친다.
이 요소들이 어떻게 설정되는지에 따라 파이프라이닝의 성능 향상이 달라진다.
이러한 중요한 요소들을 정확히 알지 못하면, 중요한 메시지가 덜 중요한 메시지 뒤로 밀려서 늦게 도착할 수 있다.
예를 들어 로드하는 중에 원래 중요하지 않다고 생각했던 리소스가 페이지 레이아웃이 완성되면서 갑자기 중요해질 수 있다.
하지만 파이프라이닝은 이를 반영하지 못하고 미리 정해진 순서대로만 리소스를 전송한다.
결과적으로, 이러한 이유들로 인해 HTTP 파이프라이닝이 제공하는 성능 향상은 대부분의 경우 크게 느껴지지 않는다.
파이프 라이닝은 HOL(Head-of-Line) 문제의 영향을 받는다.
이러한 이유로 파이프라이닝은 HTTP/2에서 사용되는 더 나은 알고리즘인 멀티플렉싱으로 대체되었다.
기본적으로 HTTP 요청은 순차적으로 실행된다.
다음 요청은 현재 요청에 대한 응답을 받은 후 발행된다.
네트워크 지연 및 대역폭 제한의 영향을 받으므로 다음 요청이 서버에 도달하기 전까지 상당한 지연이 발생될 수 있다.
파이프라이닝은 답변을 기다리지 않고 동일한 지속적 연결을 통해 연속적인 요청을 보내는 프로세스다.
이렇게 하면 연결 지연이 방지된다.
이론적으로 두 개의 HTTP 요청을 동일한 TCP 메시지에 묶으면 성능도 향상될 수 있다.
일반적인 MSS(Maximum Segment Size, 장치가 네트워크 연결에서 허용하는 가장 큰 데이터 페이로드)는 여러 개의 간단한 요청을 담을 만큼 충분히 크지만 HTTP 요청 크기에 대한 요구는 계속해서 증가하고 있다.
모든 유형의 HTTP 요청을 파이프라인으로 처리할 수 있는 것은 아니다.
오직 멱등(idempotent, 첫 번째 수행을 한 뒤 여러 차례 적용해도 결과를 변경시키지 않는 작업 또는 기능의 속성, 멱등한 작업의 결과는 한 번 수행하든 여러 번 수행하든 같다.) 메서드, 즉 GET, HEAD, PUT 및 DELETE만 안전하게 재생할 수 있다.
오류가 발생하면 파이프라인 콘텐츠를 반복할 수 있다.
오늘날 모든 HTTP/1.1 호환 프록시와 서버는 파이프라이닝을 지원해야 하지만 실제로는 많은 제한이 있다.
이는 최신 브라우저에서 기본적으로 이 기능을 활성화하지 않는 중요한 이유다.
도메인 샤딩 Domain sharding
참고 : 매우 구체적이고 즉각적인 필요가 없다면 더 이상 사용되지 않는 이 기술을 사용하지 않고 HTTP/2로 전환해야 한다.
HTTP/2에서 도메인 샤딩은 더 이상 유용하지 않다.
HTTP/2 연결은 우선순위가 지정되지 않은 병렬 요청을 매우 잘 처리할 수 있다.
도메인 샤딩은 성능에도 해롭다.
대부분의 HTTP/2 구현에서는 연결 병합이라는 기술을 사용하여 도메인 샤딩을 원래 상태(도메인 샤딩이 존재하기 전, 도메인 샤딩이 없는 상태)로 되돌린다.
HTTP/1.x 연결은 요청을 직렬화하기 때문에, 순서가 없더라도 충분히 큰 대역폭이 없으면 최적화될 수 없다.
이에 대한 해결책으로 브라우저는 각 도메인에 대해 여러 개의 연결을 열어 병렬로 요청을 보낸다.
기본적으로 2~3개의 연결을 사용하던 것이 이제는 6개의 병렬 연결을 사용하는 것이 더 일반적이다.
HTTP/1.x 연결은 요청을 순차적으로 처리하므로, 순서를 고려하지 않더라도 충분한 대역폭이 없으면 최적화될 수 없다.
HTTP/1.x는 직렬화 방식으로 요청을 처리한다.
즉, 한 번에 하나의 요청만을 서버에 보내고, 그 응답을 받은 후에야 다음 요청을 처리하러 수 있다.
이러한 방식에서는 Head-of-line blocking 문제가 발생할 수 있는데, 이는 첫 번째 요청이 완료되지 않으면 그 다음 요청들이 지연되는 현상이다.
결과적으로, 대역폭이 충분히 크지 않다면 데이터 전송 속도나 처리량이 제한되며, 여러 개의 요청을 동시에 빠르게 처리하지 못해 최적의 성능을 발휘하기 어렵다.
만약 순서를 고려하지 않는다고 해도, 충분한 대역폭이 없으면 최적화가 불가능하다.
이 문제를 해결하기 위해 브라우저는 각 도메인에 여러 연결을 열어 병렬 요청을 보낸다.
기본값은 한때 2~4개의 연결이였지만, 현재는 6개의 병렬 연결을 사용하는 것이 더 일반적이다.
이 횟수 이상을 시도하면 서버 측에서 Dos 보호가 작동할 위험이 있다.
서버가 더 빠른 웹사이트나 애플리케이션의 응답을 원할 경우, 서버는 더 많은 연결을 강제로 열도록 할 수 있다.
예를 들어, 모든 리소스를 동일한 도메인(예 : www.example.com)에 두는 대신, www1.example.com, www2.example.com, www3.example.com과 같 은 여러 도메인으로 분할할 수 있다.
각 도메인은 동일한 서버로 연결되고 웹 브라우저는 각 도메인에 6개의 연결을 연다.(위 예제에서는 18개로 늘어난다.)
이 기술을 도메인 샤딩이라고 한다.
결론 Conclusion
개선된 연결 관리를 통해 HTTP 성능을 상당히 향상시킬 수 있다.
HTTP/1.1 또는 HTTP/1.0을 사용하여 지속적 연결을 사용하면(최소한 프로세스가 실행하고 있지 않은 상태가 될 때까지) 최상의 성능으로 이어진다.
그러나 파이프라인의 실패로 인하여 더 뛰어난 연결 관리 모델이 설계되었고, 이는 HTTP/2에 통합되었다.
Connection management in HTTP/1.x - HTTP | MDN
Connection management is a key topic in HTTP: opening and maintaining connections largely impacts the performance of websites and Web applications. In HTTP/1.x, there are several models: short-lived connections, persistent connections, and HTTP pipelining.
developer.mozilla.org
'프론트엔드 > HTTP - 전' 카테고리의 다른 글
Content Security Policy (CSP) (0) | 2024.09.27 |
---|---|
Protocol upgrade mechanism (0) | 2024.09.12 |
Evolution of HTTP (0) | 2024.07.15 |
Basics of HTTP (0) | 2024.07.15 |
Choosing Between www and non-www URLs (0) | 2024.06.23 |