LabHub

네트워크 기초 · HTTP 와 TLS · 이론

HTTP — 상태 없는 프로토콜과 연결 재사용

LabHub 에서 이어서 보기

한 줄 요약

HTTP 는 요청 하나에 응답 하나를 돌려주는 상태 없는 규약이며, 성능의 역사는 그 위에서 TCP 연결을 어떻게 아껴 쓰느냐의 역사였다.

왜 이게 필요했나

HTTP/1.0 은 요청마다 TCP 연결을 새로 맺고 끊었다. 이미지 30개가 들어간 페이지를 열면 연결을 30번 맺는다. 연결 하나마다 왕복 한 번(TLS 까지 쓰면 두세 번)이 추가되므로 지연이 곧바로 사용자 체감으로 이어졌다.

어떻게 동작하나

HTTP/1.1 의 keep-alive 는 응답 후에도 연결을 열어 두고 다음 요청에 재사용한다. 왕복 비용을 크게 줄였지만 한계가 있다. 한 연결에서 응답은 요청 순서대로 나와야 한다. 앞 요청이 느리면 뒤 요청이 기다린다(응용 계층의 헤드 오브 라인 블로킹). 브라우저들이 도메인당 연결을 6개쯤 여는 방식으로 우회했고, 그래서 자원을 여러 도메인에 흩뿌리는 기법까지 유행했다.

HTTP/2 는 한 연결 안에서 요청을 스트림으로 다중화해 이 문제를 없앴다. 헤더도 압축한다. 다만 여전히 TCP 한 연결 위에 있으므로 패킷 하나가 손실되면 그 뒤의 모든 스트림이 함께 멈춘다. 응용 계층의 줄서기를 없앴지만 전송 계층의 줄서기는 남았다.

HTTP/3 는 QUIC(UDP 기반) 위로 옮겨 스트림별 독립 전달을 얻었다. 한 스트림의 손실이 다른 스트림을 막지 않는다.

메서드의 의미도 규약의 일부다. GET 은 안전하고(부수 효과 없음) 멱등하며, PUT 과 DELETE 는 안전하지 않지만 멱등하고, POST 는 둘 다 아니다. 멱등성은 재시도 가능성과 직결된다. 타임아웃이 났을 때 요청이 서버에 도달했는지 알 수 없으므로, 멱등하지 않은 요청을 무심코 재시도하면 주문이 두 번 생긴다. 그래서 결제 API 들이 멱등성 키를 요구한다.

상태 코드도 뭉뚱그리면 안 된다. 4xx 는 요청을 고쳐야 하고 5xx 는 서버 문제이므로 재시도가 의미 있을 수 있다. 특히 502, 503, 504 는 원인이 다르다. 502 는 게이트웨이가 백엔드에서 잘못된 응답을 받았고, 503 은 서비스가 스스로 감당 못 한다고 말한 것이며, 504 는 게이트웨이가 백엔드를 기다리다 지친 것이다. 로그에서 이 셋을 구분하지 않으면 엉뚱한 곳을 파게 된다.

현장에서 만나는 모습

커넥션 풀 설정이 흔한 사고 지점이다. 클라이언트는 keep-alive 로 연결을 재사용하려는데 서버나 중간 로드밸런서의 유휴 타임아웃이 더 짧으면, 서버가 막 닫은 연결에 클라이언트가 요청을 보내는 경합이 생긴다. 증상은 간헐적인 연결 재설정이고 부하와 무관하게 일정 비율로 나타난다. 클라이언트의 유휴 타임아웃을 서버보다 짧게 잡는 것이 정석이다.

이어지는 퀴즈에서 확인할 것

버전별로 무엇이 해결되고 무엇이 남았는지, 멱등성이 왜 재시도 설계의 전제인지 설명할 수 있는지 확인한다.