HTTP/0.9 (1991년)
HTTP/1.0 (1996년)
HTTP/1.1 (1997년)
HTTP/2 (2015년)
최근 많은 대규모 웹사이트에서 HTTP/2와 HTTP/3을 도입하여 사용하고 있다. 그러나, HTTP/2와 HTTP/3은 HTTP/1.1의 성능을 개선한 버전이므로, HTTP 프로토콜을 학습할 때 가장 중요하게 알아야 할 것은 HTTP/1.1이다.
아래는 각각 Google과 Naver에서 사용 중인 프로토콜의 일부이다:
이처럼 HTTP/2와 HTTP/3이 점차 확산되고 있지만, HTTP/1.1은 여전히 많은 시스템에서 사용되고 있는 핵심적인 버전이다.


서버가 클라이언트의 상태를 보존하지 않는 통신 방식을 무상태(stateless)라고 한다. 무상태 통신은 서버가 클라이언트의 이전 요청 상태를 기억하지 않기 때문에, 확장성에서 큰 이점을 제공한다. 그러나 상태 관리가 필요한 경우에는 추가적인 구현이 필요하며, 클라이언트가 요청 시 더 많은 데이터를 전송해야 하는 단점이 있다.
Stateful한 환경에서는 서버가 클라이언트의 상태를 기억하며 요청 간에 상태 정보를 유지한다. 예를 들어:
위의 대화는 인간 간의 소통 프로세스로, 점원이 클라이언트의 상태를 계속 기억하고 대화의 문맥을 유지한다.
그러나 Stateful 환경에서 서버가 다수일 경우, 아래와 같은 상황이 발생할 수 있다:
이 과정에서, 만약 점원B가 "?? 무엇을 두 개 구매한다는 거죠?"라고 물어본다면, 이는 고객의 요청 상태를 유지하지 못한 것으로, Stateful 환경에서는 불완전한 처리로 간주된다.
Stateless 세계에서는 위와 같이 질문마다 모든 정보를 포함해 요청해야 한다. 실제 현실에서는 점원이 5초 전 질문의 문맥을 기억하므로 Stateful한 소통이 자연스럽지만, Stateless 방식도 목표를 이루는 데는 문제가 없다. 다만, 소통 방식이 어색하게 느껴질 뿐이다.
Stateless의 특징은 요청이 독립적이라는 점이다. 따라서, 중간에 다른 점원(서버)으로 바뀌어도 요청 처리에 문제가 없다. 위의 비유에서 Stateful과 Stateless의 차이는 질의자가 어떤 가정을 하느냐에 달려 있다:
결과적으로, Stateless 방식은 요청마다 필요한 모든 정보를 포함하므로 서버 간 독립성이 보장되며, 확장성과 유연성을 제공한다.
이러한 무상태(Stateless)의 이점을 이해했다면, 클라이언트는 수신자가 자신의 상태 정보를 보관하지 않을 것을 전제로 요청을 보낸다. 이로 인해, 서버를 무한히 증설하는 것이 가능해진다.
예를 들어, ClientA가 서버1과 통신 중일 때 서버1에서 에러가 발생한다면, Stateful 통신에서는 서버1이 보유하고 있던 ClientA의 상태 정보를 다른 서버로 전달해야 한다. 이는 서버 간 동기화 부담을 초래하며 확장성을 제한한다.
반면, Stateless 통신에서는 중개 서버(로드 밸런서)가 ClientA의 요청을 단순히 다른 서버로 옮겨주기만 하면 된다.
클라이언트가 요청마다 필요한 상태 정보를 포함하고 있으므로, 새로운 서버에서도 요청을 문제없이 처리할 수 있다. 이로 인해 서버 증설에 대한 부담이 최소화된다(물론 서버를 늘리는 자체 비용은 제외).
결과적으로, 무상태 통신은 확장성과 유연성에서 큰 이점을 제공한다.
Stateless의 이점이 많지만, 상태 유지가 반드시 필요한 경우도 있다. 대표적인 예가 로그인 상태 유지이다.
이를 위해 브라우저 쿠키와 서버 세션 등을 활용하여 상태를 유지한다.
그러나 Stateless의 장점을 유지하기 위해, 상태 유지가 필요한 경우에도 최소한의 상태 유지 기능만 사용하는 것이 중요하다. 예를 들어, 서버에서 모든 상태를 기억하는 대신 토큰 기반 인증(JWT)을 활용하거나, 상태 정보를 클라이언트에 저장해 서버의 부담을 줄이는 방식이 선호된다.
HTTP의 비연결성은 IP의 비연결 지향성과 약간 다르다.
IP는 기본적으로 비 연결 지향적이지만, TCP의 3-way handshake를 통해 논리적 연결을 형성한다.
만약 여러 클라이언트가 서버와의 첫 통신 이후에도 계속 연결을 유지한다면, 서버의 자원이 지속적으로 소모된다.
서버는 연결을 유지하기 위해 객체를 생성하며, 이는 CPU와 메모리 자원을 점유한다.
이를 방지하기 위해 HTTP는 요청-응답이 끝난 후 TCP/IP 연결을 해제한다.
즉, 클라이언트가 다시 서버와 통신하려면 3-way handshake 과정을 반복해야 한다.
결론적으로, HTTP의 비연결성은 서버 자원의 효율적 사용을 위해 설계된 방식이지만, 연결 성립에 따른 시간 비용 증가라는 트레이드오프를 감수해야 한다.
TCP/IP 연결을 새로 맺기 위해서는 3-way handshake 과정이 필요하므로, 요청마다 연결을 반복적으로 설정하는 방식은 연결 유지 방식에 비해 시간 비용이 발생한다.
이를 해결하기 위해 HTTP Persistent Connections(HTTP 지속 연결)이 도입되었다.
HTTP/1.1부터 기본으로 지원되며, 하나의 TCP 연결을 여러 요청과 응답에 재사용하여 연결 비용을 줄이고 성능을 향상시킨다.
Connection 헤더
Connection: keep-alive를 명시하여 연결을 유지한다.여러 요청 처리
연결 종료
Connection: close 헤더를 명시하거나, 일정 시간이 지나도록 추가 요청이 없을 경우 서버가 연결을 종료한다. HTTP/2와 HTTP/3에서는 이러한 지속 연결 방식이 더욱 최적화되었으며, 멀티플렉싱과 같은 기술로 여러 요청을 동시에 처리하여 지연 시간을 대폭 감소시켰다.
HTTP 지속 연결은 시간 비용을 줄이는 장점이 있지만, 서버 자원 비용을 증가시키는 단점이 있다. 즉, Trade-off가 존재한다. 연결을 유지하려면 서버는 클라이언트당 메모리, CPU, 소켓 등의 자원을 지속적으로 할당해야 하므로, 요청 수가 폭증하는 상황에서는 서버 자원 부족 문제가 발생할 수 있다.
실제 대부분의 보통 환경에서는 요청량이 적거나 간헐적인 클라이언트 요청에 대해, Connectionless 방식이 서버 자원을 효율적으로 사용하는 경우가 많다. 연결을 종료하고 필요할 때 다시 연결을 설정하므로, 유휴 연결로 인한 자원 낭비를 방지할 수 있다.
Google 검색(지속 연결):
Google은 HTTP 지속 연결을 사용하지만, 워낙 요청량이 많기 때문에 로드 밸런싱과 커넥션 풀링 기술을 함께 활용하여 효율성을 극대화한다. 이러한 구조로도 서버 자원 부담이 커지는 경우가 많아, 필요에 따라 연결을 종료하거나 다른 서버로 요청을 분산시킨다.
RESTful API(비연결성):
대부분의 REST API 설계에서는 Connectionless 방식을 기본으로 채택한다. 요청이 독립적으로 처리되며, 응답 후 연결이 종료되므로 서버 자원 사용량이 낮다. 상태 정보를 유지하지 않으므로 확장성이 높은 설계가 가능하다.
대형 스트리밍 서비스(Netflix, YouTube)(지속연결):
이와 같은 서비스는 HTTP 지속 연결을 적극 활용한다. 지속적인 데이터 스트리밍이 필요하기 때문에, 연결을 유지하면서 데이터를 효율적으로 전송한다. 이 경우에도 서버 자원 문제를 최소화하기 위해 QUIC(HTTP/3)를 도입하여 전송 효율을 높이고 연결 설정 비용을 줄인다.
HTTP 지속 연결과 Connectionless 방식은 각각의 장단점이 있으므로, 사용 환경과 애플리케이션의 특성에 따라 선택하는 것이 중요하다. 요청이 독립적이고 간헐적인 경우 Connectionless 방식이 적합하며, 실시간 스트리밍처럼 지속적인 데이터 전송이 필요한 경우 지속 연결 방식이 적합하다.