HTTP keep-alive와 Persistent Connection

mylime·2024년 8월 21일
1
post-thumbnail

이 포스팅은 2024.08.21에 작성되었습니다.


<수정사항>

  • 24.12.08: Keep-Alive의 명시적 종료: 간단하지 않다!, Keep-Alive 통신이 지속되는 동안 OS자원은 계속 낭비된다 내용 추가



서론


부하테스트를 공부하면서 keep-alive 설정이 부하테스트에 영향을 줄 수 있다는 걸 알게되었다. keep-alive는 http 헤더에서 자주 마주친 친구였는데, 지속적인 연결을 하나보다 생각하고 넘어갔었다. 하지만 생각해보면 http는 stateless한 특징을 가지고있고, 지속적인 연결이 되면 안되는 게 아닌가 하는 의문이 생겼다. 그러면서 keep-alive에 대한 궁금증이 생겼다. Http의 keep-alive 설정에 대해 더 알아보고 포스팅해보고자 한다!



HTTP 지속 연결


HTTP 프로토콜은 요청 간 사용자 데이터를 저장하는 수단을 제공하지 않는다.

HTTP는 stateless한 특징을 가지므로 request&response가 끝난 후 상태가 끊긴다. 하지만 웹 사이트를 통해 Http 통신을 할 때, 실제로는 서버에 동일한 클라이언트가 연속적으로 요청을 보내는 경우가 많다. (이를 site locality라고 한다)

지금 당장 내 블로그에서 개발자도구만 켜봐도 이미지, 자바스크립트, css파일 등 한 번에 굉장히 많은 요청을 보내고 받는 걸 확인할 수 있다. 이렇게 연속적으로 요청을 보내는데 계속 TCP를 연결하는 과정이 추가되면 페이지 로딩 시간도 늘어나고 비효율적일 것이다.

이러한 비효율을 해결하기 위해 HTTP/1.1(및 향상된 HTTP/1.0 버전)은 트랜잭션 완료 후 TCP 연결을 유지하고, 미래의 HTTP 요청에 기존 연결을 재사용할 수 있게 하였다.


기존 연결을 재사용할 때의 장점

TCP/IP는 접속 시 1.5RTT를 필요로한다. TLS의 경우 핸드셰이크 과정에서 2RTT만큼의 시간이 걸린다.
Keep-Alive를 통해 연결을 유지하고, 기존 연결을 재사용하면 TCP/SSL연결 과정이 축소되며 request 수가 줄어들고, 통신 처리량이 증가하면서 사용자는 속도가 올라간 것처럼 느낄 수 있다.

  1. 네트워크 혼잡 감소
  2. 네트워크 비용 감소
  3. Latency 감소

+) Persistent Connection은 Parallel Connection과는 다르다

Parallel Connection은 병렬적으로 동시에 여러 Connection을 맺는 방법으로, Persistent Connection과 다르다. 많은 웹 어플리케이션은 Parallel Connection과 Persistent connection울 적절히 혼용해서 사용된다.



HTTP에서 지속 연결을 구현하는 방법


Http에서 persistent connection은 두 가지 유형이 있다. HTTP/1.0+ "keep-alive"연결HTTP/1.1 "persistent"연결이다.



📌HTTP/1.0+ keep-alive Connection

HTTP keep-alive, a.k.a., HTTP persistent connection, is an instruction that allows a single TCP connection to remain open for multiple HTTP requests/responses.

Http keep-alive 설정은 persistent connection을 맺는 기법 중 하나로, 여러 Http 요청/응답에 대해 단일 TCP연결이 열려있도록 하는 명링이다. 이를 통해 한 페이지를 로딩하며 여러 데이터를 불러올 때 단일 연결로 제공받을 수 있다.


(이미지 출처: imperva - Keep Alive)


HTTP/1.0+ Keep-Alive의 동작과정

서버와 클라이언트 간 Keep-Alive가 동작하는 규칙은 다음과 같다.

  1. HTTP/1.0 keep-alive connection을 구현하는 클라이언트는 Connection: Keep-Alive 요청 헤더를 포함하여 연결이 열린 상태로 유지되도록 요청한다
  2. 서버가 다음 요청을 위해 연결을 연어두려 하면 응답에 동일한 헤더로 응답한다.



keep-alive 설정 파라미터

Keep-Alive 설정에 사용할 수 있는 파라미터는 2가지가 있다. 이 설정은 Keep-Alive: 뒤에 쉼표로 구분해서 붙이면 적용이 된다. (물론 Connection: Keep-Alive도 같이 있어야 동작한다)

  • timeout: 연결이 계속 열려있어야 하는 최소한의 시간
  • max: 연결이 닫히기 이전에 전송될 수 있는 최대 요청 수(연결을 유지할 가능성이 있는 추가 HTTP 트랜잭션 수)

서버가 최대 5개의 추가 트랜잭션에 대해 or 2분 동안 유휴 상태가 될 때까지 연결을 열린상태로 유지하려면 다음과 같이 설정해주면 된다.

Connection: Keep-Alive
Keep-Alive: max=5, timeout=120



📌HTTP/1.0+ keep-alive의 결함

However, some experimental implementations of HTTP/1.0 persistent connections are faulty; for example, if an HTTP/1.0 proxy server doesn't understand Connection, it will erroneously forward that header field to the next inbound server, which would result in a hung connection.
(rfc9112)

많은 HTTP/1.0 브라우저와 서버는 keep-alive connection이라는 초기 실험적 단계의 지속적 연결을 지원하도록 확장되었지만, Http/1.0+의 keep-alive의 일부 실험적 구현은 결함이 있었다.

Connection: Keep-Alive는 클라이언트에서 나가는 단일 TCP 연결에만 영향을 준다. 하지만 단순 프록시는 이 헤더를 제거하지 않고 그대로 전달하기 때문에 문제가 발생할 수 있다. 이로 인해 클라이언트와 서버 모두가 연결이 지속된다고 잘못 인식할 수 있고, 해당 필드를 다음 서버로 잘못 전달하여 연결이 중단되는 문제가 발생할 수 있다.


이 문제를 해결하기 위해 Proxy-Connection 헤더가 도입되었지만, 단일 프록시 상황에만 효과가 있었고, 프록시는 종종 여러 계층에 배포되기 때문에 문제가 다시 발생할 수 있다.

결과적으로 클라이언트는 어떤 요청에서도 Proxy-Connection 헤더 필드를 보내지 않도록 권장된다고 한다. keep-alive 또한 현재 더 이상 사용되지 않으며, 현재 HTTP/1.1 사양에 더 이상 문서화도 되어있지 않다.



📌HTTP/1.1 Persistent Connection

HTTP/1.1은 기본적으로 Persistent Connection을 사용한다.

HTTP/1.1은 keep-alive 연결 지원을 중단하고, 대신 Persistent Connection이라는 향상된 설계를 도입했다. 이 설계에서는 명시적으로 Connection: close 헤더가 없는 한 모든 연결이 기본적으로 지속된다. 클라이언트 또한 응답에 close가 포함되지 않는 한 연결이 열려있다고 가정한다. (+timeout 시간이 지나도 close된다 관련링크)


Persistent Connection을 사용하며 지켜야할 규칙은 다음과 같다.

  • Connection:close 요청을 보낸 후에는 해당 연결에서 더 이상 요청을 보낼 수 없음
  • 모든 메시지에 올바른 Content-Length가 있어야 하며, 그렇지 않으면 연결이 유지될 수 없음
  • HTTP/1.1 프록시는 클라이언트 및 서버와 별도로 지속연결을 해야함
  • HTTP/1.0 클라이언트와는 지속 연결을 설정하지 않아야함
  • HTTP/1.1 장치는 연결을 언제든지 닫을 수 있지만, 중간에 닫지 않도록 해야 하며, 최소한 하나의 요청에는 응답을 제공해야 함
  • 클라이언트는 연결이 닫힐 경우 요청을 재시도할 준비가 되어 있어야 하며, 단일 사용자 클라이언트는 서버나 프록시에 대해 최대 두 개의 지속 연결만 유지해야 함

keep-alive 헤더 필드는 HTTP/1.0 서버와의 지속 연결을 가능하게 할 수 있지만, 이를 사용하는 클라이언트는 "hung(중단된)" 요청이 발생하는지 모니터링해야 하며(이 경우 클라이언트는 이 헤더 필드를 보내는 것을 중지해야 함), 프록시가 사용되는 경우에는 이 메커니즘을 전혀 사용하지 않는 것이 좋다고 한다.


+) Keep-Alive의 명시적 종료: 간단하지 않다!

통신 종료가 규정되어 있긴 하지만, 모든 통신이 확실히 끝났는지를 서버가 판정할 수 없다. js를 이용하면 동적으로 요청을 발신할 수도 있으므로, HTML을 정적으로 해석하는 것만으로 클라이언트 측에서 완전히 통신을 완료했는지 여부를 판단할 수 없다고 한다. 그래서 실제로는 명시적으로 종료하기 보단 실제 타임아웃으로 접속이 끊어지길 기다린다고 한다! (Real World HTTP 참고)



+) Keep-Alive 통신이 지속되는 동안 OS자원은 계속 낭비된다

그래서 실제로 통신이 이루어지지 않는데 접속을 유지하는 건 바람직하지 않다!



+) HTTP/2.0에서 지속적 연결 구현

HTTP/2.0은 Multiplexed Stream을 통해 한 커넥션에서 여러 메시지를 주고받을 수 있다. 이 기능은 HTTP/1.1의 keep-alive 뿐만 아니라 pipelining이 가지고 있던 문제를 해결한다.



마치며..


동작방식과 장점 정도만 알아가려고 했는데, 자료를 조사하다보니 HTTP의 발전 대해 더 공부해보고 싶어졌다. 주변 지인분께 HTTP 관련 책(HTTP 완벽 가이드)을 추천받았는데 읽어보면서 조금 더 HTTP를 공부해보려고 한다.







참고자료


https://etloveguitar.tistory.com/137
https://www.imperva.com/learn/performance/http-keep-alive/
https://httpwg.org/specs/rfc9112.html
https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Keep-Alive
https://en.wikipedia.org/wiki/HTTP_persistent_connection
https://www.oreilly.com/library/view/http-the-definitive/1565925092/ch04s05.html

  • Real World HTTP 도서
profile
깊게 탐구하는 것을 좋아하는 백엔드 개발자 지망생 lime입니다! 게시글에 틀린 정보가 있다면 지적해주세요. 감사합니다. 이전블로그 주소: https://fladi.tistory.com/

0개의 댓글