HTTP는 애플리케이션 계층의 프로토콜이지만 그 성능과 안정성은 결국 TCP 커넥션 관리에 크게 의존한다. 단순히 요청과 응답만 오가는 것처럼 보이지만 실제로는 연결 수립(TCP 3-way handshake), 종료, 재사용, 파이프라이닝, 병렬성 같은 커넥션 관리 전략이 성능에 직접적인 영향을 준다. 특히 웹 브라우저와 서버 사이의 통신 효율을 높이기 위해 커넥션을 어떻게 열고 닫을지, 또 몇 개를 동시에 유지할지가 핵심적인 고려 요소가 된다.
TCP 커넥션은 연결을 맺기 위해 클라이언트와 서버가 세 번의 왕복 메시지를 주고받는 3-way handshake 과정을 거쳐야 한다. 이 단계는 필연적으로 지연을 발생시키며 커넥션 종료 시에도 FIN과 ACK 절차를 거치면서 네트워크 자원이 소모된다. 또한 네트워크 RTT(Round Trip Time), 큐잉 지연, 혼잡 제어와 같은 요인들도 성능에 영향을 준다. 특히 TCP는 새로운 연결에서 전송 속도를 조금씩 올려가는 느린 시작(Slow Start) 알고리즘을 사용하기 때문에 요청마다 새로운 연결을 여는 방식은 불필요한 오버헤드를 발생시켜 성능을 크게 떨어뜨린다.
HTTP/1.0의 기본은 비지속 커넥션으로 요청과 응답을 한 번 교환한 후 곧바로 커넥션을 종료한다. 이 방식은 단순하지만 이미지, CSS, JS 같은 다수의 리소스를 불러와야 하는 웹 페이지에서는 비효율적이다. 매번 새로운 연결을 맺어야 하므로 연결 지연과 TCP handshake 반복 문제가 발생한다. 이를 개선하기 위해 도입된 것이 지속 커넥션(Keep-Alive)이다. Connection: keep-alive
헤더를 사용하면 여러 요청과 응답을 하나의 TCP 커넥션에서 처리할 수 있어 연결 및 종료 비용을 줄이고 네트워크 효율성을 높일 수 있다. 다만 유휴 연결을 장시간 유지하면 서버 자원이 고갈될 위험이 있어 적절한 관리가 필요하다. 또한 초기에는 오래된 프록시나 게이트웨이가 Keep-Alive를 잘못 처리하는 경우도 있어 호환성 문제가 지적되기도 했다.
지속 커넥션 위에서는 파이프라이닝 기법이 사용될 수 있다. 파이프라이닝은 여러 요청을 순차적으로 한꺼번에 보내고 서버는 이를 순서대로 응답하는 방식이다. 이를 통해 각 요청마다 RTT를 기다릴 필요가 없어 응답 속도를 개선할 수 있다. 그러나 특정 응답이 지연되면 뒤에 대기 중인 응답들도 함께 지연되는 Head-of-line Blocking 문제가 발생한다. 게다가 서버와 프록시 구현이 파이프라이닝을 제대로 지원하지 않는 경우가 많아 실무에서는 널리 활용되지 못했다.
브라우저는 성능을 개선하기 위해 도메인당 여러 개의 TCP 연결을 동시에 열어 요청을 병렬로 처리한다. 일반적으로 6개 내외의 연결을 허용하는데 이렇게 하면 병목 현상을 줄이고 여러 리소스를 동시에 다운로드할 수 있다. 하지만 커넥션 수가 많아지면 TCP 혼잡 제어 효율이 떨어지고 네트워크 오버헤드가 증가한다는 단점이 있다. 그래서 브라우저마다 도메인당 커넥션 개수를 제한하는 정책을 두고 있으며 이는 사용자 경험과 네트워크 자원 소비 간의 균형을 맞추기 위한 것이다.
커넥션 관리 전략은 상황에 따라 다르게 적용된다. 짧은 리소스를 빠르게 내려받아야 한다면 병렬 커넥션이 유리하고 장시간 연결을 유지해야 한다면 Keep-Alive를 통해 커넥션 재사용을 극대화하는 것이 효과적이다. 대규모 트래픽 환경에서는 커넥션 풀링을 적용해 자원을 효율적으로 관리할 수 있으며 HTTP/2 이후로는 멀티플렉싱 기술이 도입되어 파이프라이닝과 병렬 커넥션의 한계를 동시에 해결할 수 있게 되었다. 다만 HTTP/2는 여전히 TCP 기반이기 때문에 하나의 패킷 손실이 전체 스트림에 영향을 주는 Head-of-line Blocking 문제는 남아 있다. 이를 해결하기 위해 최신 프로토콜인 HTTP/3(QUIC, UDP 기반)이 등장하여 더 빠르고 안정적인 커넥션 관리 방식을 제공한다.
HTTP는 요청과 응답의 교환 자체보다 커넥션을 어떻게 관리하느냐가 성능 최적화의 핵심이라는 점을 다시금 알게 되었다. 특히 이미지, CSS, JS처럼 수십 개의 리소스를 동시에 불러오는 웹 브라우저 환경에서 비지속 → 지속(Keep-Alive) → 파이프라이닝 → 병렬 커넥션 → HTTP/2 멀티플렉싱 → HTTP/3(QUIC)으로 발전해온 흐름은 매우 자연스러운 진화 과정이었다. 앞으로 프로젝트에서 API 서버나 클라이언트를 설계할 때 단순히 로직만 고민할 것이 아니라 커넥션 재사용과 풀링 전략까지 고려해야 서비스 품질을 보장할 수 있음을 배웠다.