keep alive. 그동안 Http에서의 Keep alive 개념은 대충은 알고 있었지만, TCP에서의 Keep alive는 솔직히 잘 모른다고 할 정도로 지식이 없었습니다.
그러나 최근 이 keep-alive에 대해 생각해 볼 기회가 있었기도 하고🧐, 한 번 개념을 제대로 알아볼 필요가 있다고 생각되어 오늘의 주제로 선택하게 되었습니다.
Keep-Alive는 Connection을 유지하기 위한 메커니즘입니다.
다만 Http와 TCP 모두 똑같은 Keep-Alive라는 이름이기에 동일한 것으로 헷갈릴 수 있지만, 두 개는 완전 다른 개념이라는 것을 유념할 필요가 있습니다.
오늘은 Http와 TCP에서의 Keep-Alive는 무엇을 의미하는지, 두 가지에서 어떤 차이점이 있는지 한 번 알아보고 작성해보려 합니다.
1. HTTP의 Keep-Alive란?
HTTP의 프로토콜은 원래 요청 - 응답 단위의 통신을 기반으로 합니다.
클라이언트가 서버에 요청을 보내면 응답을 받고, 그다음 연결을 끊어버리는 방식입니다.
하지만 모든 요청에 매번 연결을 새로 만들고 끊고, 매번 이렇게 연결을 새로 만드는 건 비용과 리소스의 낭비가 큽니다.
TCP 핸드셰이크도 다시 해야 하고, 만약 연결이 끊어지면 재연결 과정에서 지연도 발생하니까요.
HTTP Keep-Alive
그래서 등장한 것이 바로 이 HTTP의 Keep-Alive입니다.
HTTP의 Keep-Alive는 클라이언트와 서버 사이에서 통일한 TCP 연결을 이용해 여러 번 요청을 보내기 위해 사용합니다.
여러 개의 요청을 하나의 TCP Connection에서 진행하기 때문에 TCP 연결을 위한 3-way handshake는 첫 번째 이후로 새롭게 맺지 않습니다.
HTTP 서버는 TCP Connection을 Keep-Alive 시간 동안 끊지 않고 기다립니다.
마지막 요청으로부터 Keep-Alive 시간이 지난다면 HTTP 서버에서 해당 TCP 연결을 끊습니다.
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8
Keep-Alive: timeout=5, max=1000
Server: Apache
(body)
보통 위와 같은 응답을 받는 걸로 Keep-Alive를 확인할 수 있습니다.
- Connection
- Keep-Alice
- Close : 만약 Connection이 Close로 왔다면, Keep-Alive를 해당 서버에서 사용하지 않거나, 사용하지 못한다는 것을 알 수 있습니다.
- Keep-Alive
- timeout : 연결이 열려 있어야 하는 최소한의 시간을 초 단위로 표기합니다.
다만, keep-alive TCP 메시지가 전송 계층에 설정되지 않으면 TCP 타임아웃 이상의 타임아웃은 무시됩니다. - max : 연결이 닫히기 전에 요청될 수 있는 최대 요청수를 의미합니다.
이 수보다 더 많은 요청을 주고받을 경우에는 connection은 close 됩니다.
- timeout : 연결이 열려 있어야 하는 최소한의 시간을 초 단위로 표기합니다.
그 외 Keep-Alive 옵션 규칙
- 정확한 Content-length를 사용해야 한다. 하나의 connection을 계속해서 재사용해야 하는데, 정확한 length를 사용하지 않으면 특정 요청의 종료를 판단하기 어렵기 때문입니다.
- 클라이언트는 언제는 connection이 닫힐 수 있기 때문에 retry 로직을 준비해둬야 합니다.
- Connection 헤더를 지원하지 않는 proxy에는 사용할 수 없습니다.
저희가 대부분 사용하는 HTTP 1.1 이후부터는 Keep-Alive가 기본 동작으로 설정이 되어있기 때문에, 명시적으로 Connection: Close를 해 주어야만 연결을 끊습니다.
반면 Http 1.0에서는 기본 동작으로 설정되어있지 않아, Connection: Keep-Alive 헤더를 명시적으로 넣어줘야 작동합니다.
장점
- TCP 연결에서 오버헤드 감소 : 3-way-handshake 반복을 제거하기 때문에 오버헤드가 감소한다는 장점이 있습니다
- 웹 페이지 로딩 속도 향상 : 오버헤드가 감소하는 만큼 여러 이미지나 JS, CSS 요청 시 효과적입니다.
2. TCP의 Keep-Alive란?
자, 이제 HTTP에서 한 단계 내려가 TCP의 Keep-Alive를 살펴보도록 하겠습니다.
TCP Keep-Alive는 HTTP의 Keep-Alive와는 전혀 다른 목적을 갖고 있는 개념입니다.
TCP에서의 Keep-Alive는 TCP 연결이 맺어진 이후 해당 연결을 유지하는 것에 대해서 작은 패킷을 보내며 체크하는 메커니즘을 말합니다.
사실 간단하게 비교해 보면 애플리케이션 레벨에서의 연결 유지를 의미하는 HTTP와 달리,
TCP의 Keep-Alive는 네트워크 레벨에서의 연결 상태 확인을 위한 기술입니다.
TCP는 기본적으로 상태를 추적하는 연결형 프로토콜입니다.
그런데 만약 클라이언트가 갑자기 죽어버렸다면?
서버 입장에선 상대방이 연결을 끊었는지, 네트워크 장애가 생긴 건지, 그냥 너무 오래 대기 중인 건지 알 수가 없죠.
이때 TCP Keep-Alive 옵션이 활성화되어 있다면, 일정 시간 동안 통신이 없을 경우 OS가 알아서 "살아있니?"라고 확인하는 패킷을 주기적으로 날립니다.
이건
- 이건 애플리케이션 코드와는 별개로 동작합니다.
- 주기는 OS마다 다르며, 보통 수 분~수 시간 단위로 느립니다.
- 응답이 없으면 해당 연결은 죽었다고 판단하고 정리합니다.
만약 Keep-Alive 옵션이 없다면, 다음 실제 Packet이 전달되기 전까지 연결이 정상인지 아닌지 알 수 없게 되는 겁니다.
즉, TCP Keep-Alive는 죽은 연결을 정리하는 용도에 가깝다고 보면 됩니다.
net.ipv4.tcp_keepalive_time=200
net.ipv4.tcp_keepalive_intvl=200
net.ipv4.tcp_keepalive_probes=5
HTTP와는 조금 다른 형태를 가지고 있는 걸 확인할 수 있습니다.
- tcp_keepalive_time : 최초 keepalive를 보내는 시간
- tcp_keepalive_probes : 응답이 없으면 추가로 보내는 횟수
- tcp_keepalive_intvl : 추가로 보낼 때의 간격
3. 언제 쓰일까?
- HTTP Keep-Alive
- 대부분의 웹 서버 (Nginx, Apache, Node.js 등)에서 기본적으로 활성화되어 있습니다.
- 요청 처리 성능을 높이기 위해 거의 필수처럼 사용되는 기능입니다.
- 프록시 서버나 로드밸런서 앞단에서 Keep-Alive 설정을 조절해 리소스 낭비를 줄이거나 연결 수를 제한할 수 있습니다.
- TCP Keep-Alive
- 보통 장시간 연결이 필요한 서비스 (eg. 메시징 서버, 소켓 기반의 서비스 등)에서 유용합니다.
- 예를 들어, 클라이언트가 죽었는지 서버가 감지해야 하는 경우, TCP Keep-Alive를 설정해 놓으면 zombie connection을 방지할 수 있습니다.
- 하지만 기본 설정 주기가 너무 느려 실시간 서비스에는 적합하지 않을 수 있고, 이 경우는 애플리케이션 레벨에서 ping/pong 메시지를 구현하기도 합니다.
오늘은 이렇게 keep alive가 어떤 기능인지.
HTTP와 TCP에서의 차이가 무엇인지, 어떤 기능을 가지고 있는지 알아봤습니다.
사실 keep alive는 http에서 어떻게 작동되는지는 어렴풋이 알고 있었지만, tcp에서는 어떻게 작동되는지 잘 몰랐는데 두 가지가 확실하게 차이가 있다는 것을 확인할 수 있었습니다.
출처
- https://developer.mozilla.org/ko/docs/Web/HTTP/Reference/Headers/Keep-Alive
- https://sabarada.tistory.com/262
- https://etloveguitar.tistory.com/137