HTTP Keep-Alive: HTTP/1.1 지속 연결과 HTTP/2·3 연결 재사용

반응형

HTTP Keep-Alive는 요청마다 connection을 새로 맺지 않고 여러 HTTP exchange에 재사용하는 개념이다. 다만 HTTP/1.1에서는 persistence가 기본이고, HTTP/2·3에서는 여러 stream이 하나의 connection을 함께 쓴다. 모든 version을 Connection: keep-alive header 하나로 설명하면 오히려 헷갈린다.

HTTP/1.1은 persistent connection이 기본이다

RFC 9112의 persistence 규칙에 따르면 HTTP/1.1 connection은 기본적으로 persistent하다. client나 server가 현재 response 뒤에 connection을 닫으려면 Connection: close option으로 의도를 알린다.

GET /articles/358 HTTP/1.1
Host: example.com
Connection: close

따라서 HTTP/1.1에서 다음 header를 반드시 보내야 persistence가 켜진다는 설명은 정확하지 않다.

Connection: keep-alive

이 명시적 negotiation은 HTTP/1.0 구현과의 compatibility에서 주로 등장한다. HTTP/1.0에서도 일부 구현이 Keep-Alive extension을 지원했으므로 “HTTP/1.0은 항상 요청마다 새 TCP connection을 만든다”라고 단정할 수도 없다.

또한 Connection은 hop-by-hop header다. proxy가 있는 경로에서는 client-proxy와 proxy-origin connection의 lifetime이 서로 다를 수 있다. browser에서 보이는 한 request header만으로 origin까지 같은 socket이 유지됐다고 결론 내리면 안 된다.

무엇을 아끼고 무엇을 더 사용하나

connection reuse가 유리한 이유는 새 transport connection을 만드는 비용을 반복하지 않기 때문이다. HTTPS라면 TCP connection setup뿐 아니라 TLS handshake의 비중도 고려해야 한다. 이미 열린 connection에 다음 request를 보낼 수 있으면 latency와 handshake traffic을 줄일 가능성이 크다.

그렇다고 항상 CPU·memory·bandwidth가 모두 줄어드는 것은 아니다.

  • idle connection도 file descriptor와 socket buffer를 차지한다.
  • server, load balancer, reverse proxy, client의 idle timeout이 서로 다르면 재사용 직전에 connection이 끊길 수 있다.
  • HTTP/1.1 connection 하나에서는 response ordering과 application behavior 때문에 concurrency가 제한될 수 있다.
  • 너무 많은 connection을 오래 붙잡으면 다른 client가 쓸 resource가 줄어든다.

RFC 9112도 inactive connection timeout의 길이를 protocol이 강제하지 않으며 어느 endpoint든 connection을 닫을 수 있다고 설명한다. tuning의 목표는 가장 긴 timeout이 아니라 request pattern에 맞는 reuse와 회수의 균형이다.

HTTP/1.1, HTTP/2, HTTP/3의 차이

version transport와 request 처리 connection reuse 관점
HTTP/1.1 보통 TCP 위에서 request-response를 순서대로 처리 한 connection에 여러 exchange를 순차 재사용
HTTP/2 TCP connection 안에 여러 stream을 multiplex 여러 request를 concurrent stream으로 함께 처리
HTTP/3 QUIC connection 안에 stream을 사용 여러 request에 persistent QUIC connection을 재사용

RFC 9113은 HTTP/2 connection 안에 여러 stream을 두고 multiplexing과 flow control을 수행하는 방식을 정의한다. 이는 HTTP/1.1 pipelining과 다르다. 다만 모든 stream이 같은 TCP connection을 공유하므로 packet loss에 따른 TCP-level head-of-line 영향까지 사라지는 것은 아니다.

RFC 9114은 HTTP/3가 QUIC의 stream-based multiplexing을 사용하고, HTTP/3 connection을 여러 request에 persistent하게 재사용하도록 설명한다. HTTP/3라고 해서 connection lifetime을 신경 쓸 필요가 없어지는 것이 아니다. certificate authority, endpoint, idle timeout, GOAWAY와 connection closure를 여전히 다뤄야 한다.

Python requests에서 connection pool을 재사용한다

requests.Session은 cookie와 공통 설정을 유지하고 urllib3의 connection pool을 사용한다. 같은 host에 여러 request를 보낼 때 적절한 pooled connection을 재사용할 수 있다.

import requests

with requests.Session() as session:
    session.headers.update({"User-Agent": "connection-reuse-example/1.0"})

    for path in ("/", "/robots.txt"):
        response = session.get(
            f"https://example.com{path}",
            timeout=(3.05, 10),
        )
        response.raise_for_status()
        _ = response.content
        print(path, response.status_code)

이 예제가 “항상 정확히 하나의 TCP connection만 쓴다”는 뜻은 아니다. host, redirect, concurrency, server closure, pool 상태에 따라 새 connection이 필요할 수 있다. Requests Session 문서가 강조하듯 response body를 모두 읽거나 response를 닫아야 connection이 pool로 돌아가 재사용될 수 있다. network call에는 connect와 read timeout도 명시하는 편이 안전하다.

운영에서 확인할 항목

  1. protocol version을 확인한다. HTTP/1.1 header만 보고 HTTP/2·3 behavior를 추측하지 않는다.
  2. client, CDN, load balancer, proxy, application server의 idle timeout을 각각 기록한다.
  3. request rate, active·idle connection, new connection rate, reset, TLS handshake latency를 함께 본다.
  4. streaming response는 body 소비와 close 시점이 일반 response와 다름을 확인한다.
  5. timeout을 늘린 뒤 latency만 보지 말고 file descriptor와 memory pressure도 검증한다.

connection 자체의 TCP state와 packet flow는 TCP 연결 과정, HTTPS에서 추가되는 handshake는 TLS 1.3 handshake와 함께 보면 경계가 선명해진다.

정리

HTTP/1.1에서 persistence는 기본이며 Connection: keep-alive가 필수 switch가 아니다. HTTP/2와 HTTP/3도 connection reuse가 중요하지만 여러 stream을 multiplex한다는 점이 다르다. 성능 개선 여부는 header 존재가 아니라 실제 connection reuse rate, timeout alignment, response consumption, resource pressure로 판단해야 한다.

참고 자료

반응형
KEEP READING
카테고리 전체 보기 →

댓글