Back

keep-alive

사용자가 다른 외부 서비스 링크를 클릭하여 현재 브라우저의 페이지가 종료될 때 안전하게 요청을 보내도록 구현하는 방법을 찾던 중이었다.

Reliably Send an HTTP Request as a User Leaves a Page | CSS-Tricks

여러 해결 방법 중에 하나를 확인했는데, http요청을 보존시키는 옵션에 대한 내용과 함께 keep-alive 플래그를 사용하라는 내용이 있었다.

이 keep-alive가 뭔지 모르기도 했으며, Postman을 사용하다보면 헤더에 Connection이라는 key는 keep-alive라는 value를 가지고 있는 것이 기본 설정으로 되어있던 것도 떠올랐다. 이 때문에 갑자기 이것에 대해 궁금해졌고 알아보게 되었다.

일단 keep-alive 자체는 tcp와 http에서 persistent connection을 유지하기 위해 제공되는 옵션이다.

http는 tcp 기반으로 동작하고, tcp전송이 끝나면 연결이 끊어져 http도 서로 전송이 끝나면 끊어진다. 애초에 http 자체가 connectionless, stateless하기 때문에 처음에는 이랬지만, 비효율성을 인지하고 keep-alive 옵션이 추가되었다.

이를통해 동일한 주소로 요청을 할 때마다 새로운 연결설정을 하고, 다시 끊는 비효율적인 리소스 낭비 (클라이언트와 서버 사이의 handshake 과정)를 줄일 수 있으며, 성능 향상도 기대할 수 있다.

http/1.0은

Connection: Keep-alive // 연결 유지
Connection: close // 연결 종료

다음과 같이 설정을 해야 한다. 하지만 http/1.1부터는 별도의 설정 없이 기본적으로 keep-alive로 동작한다.

response header 쪽에 아래와 같이 담겨서 온다

Keep-Alive: timeout=5, max=20

이 뜻은 마지막 요청으로부터 5초동안 연결을 유지하며, 최대 20개까지 유지한다는 뜻이다.

따라서 이 다음 요청으로 부터 온 응답의 max 값은 19로 오게될 것이다.

처음에 이것의 목적에 대해 잘 몰랐다. 이를 아주 오랫동안 연결시키는 것인줄 알았다. 하지만 예제들의 대부분의 timeout이 몇 초단위인 것으로 봐서는 한번에 여러가지 요청을 동시에 하게 될 경우에 이 여러 요청들 사이마다 다시 새로운 연결설정을 하지 않고 바로 요청을 보낼 수 있도록 하기 위함인 것 같다.

이것은 잠깐 http/1.0+의 문서에서는 내용을 찾을 수 있지만, http/1.0, http/1.1의 표준은 아니라고 한다. http/1.1 에서는 Connection: close 헤더를 명시했을 때만 커넥션을 끊고, 나머지는 모두 지속하는 것으로 관리하도록 되었기에 빠지게 되었으며, Connection: Keep-Alive를 굳이 넣게되면 또다른 문제가 생긴다.

Connection: keep-alive를 사용했을 때의 문제

프록시를 사용하며, 해당 헤더를 지원하지 않는 프록시라면, 문제가 생긴다. (http/1.0과 같이..) 이를두고 dump proxy라고 부르는 것 같다.

클라이언트가 connection 유지를 위해 프록시에게 해당 요청을 보냈을 때 프록시가 이게 무엇을 의미하는지 모르게 된다면, 이를 서버에 그대로 전송을 하게 된다.

서버는 keep-alive가 포함된 요청을 받았기에 응답에도 keep-alive를 보낸다. 프록시는 뭔지도 모르고 클라이언트에 그냥 그대로 응답해준다.

프록시는 이후 서버가 연결을 끊기를 기다린다. 하지만, 서버에는 아무런 요청이 없어 프록시의 커넥션은 살아있고 계속 대기를 하게된다.

클라이언트는 keep-alive를 동의했다고 판단하여 다음 요청을 프록시에게 보낸다. 하지만 프록시는 같은 커넥션에서 다른 요청이 오는 것을 예상하지 못했기 때문에 프록시는 이 요청을 무시하게된다.

서버역시 keep-alive를 동의했기 때문에 처음 연결했던 connection으로 부터 추가적인 요청이 오기만을 기다린다.

이런 문제들 때문에 표준에서 제거가 되었다고 한다.