HTTP keep-alive

Kyle·2021년 12월 22일
4
post-thumbnail

TCP, 웹서버, HTTP 관점에서 keep-alive란 무엇인지 알아보고, HTTP keep-alive 통신을 하는 클라이언트 입장에서 주의해야 할 사항에 대해서도 함께 알아보겠습니다.

keep-alive란?

서버와 클라이언트가 맺은 연결을 유지하는 방식을 의미합니다.

'연결을 얼마나 유지할지'와 같은 keep-alive 속성은 두 곳에서 관리가 됩니다. 운영체제 커널에서 관리되는 TCP keep-alive, 웹 서버에서 관리되는 웹 서버 keep-alive 이렇게 두 가지가 있습니다.

HTTP와 같은 일반적인 웹 서버 통신은 웹 서버의 keep-alive의 속성을 따릅니다. 반면에 Rabbit MQ, Active MQ, Thrift RPC 등 TCP 통신은 TCP keep-alive 속성을 따릅니다.

자신이 운영하는 서버가 TCP keep-alive의 속성을 따르고 있는지, 웹 서버의 keep-alive 속성을 따르고 있는지 알아야 합니다.

TCP keep-alive, 웹 서버 keep-alive의 차이에 대해 알아보겠습니다.

1. TCP keep-alive

TCP keep-alive를 이용하는 경우에는 운영체제 커널에서 관리합니다.

운영체제 커널에서 관리되는 keep-alive 옵션의 종류는 다음과 같습니다.

> sysctl -a | grep keepalive

net.ipv4.tcp_keepalive_timeout = 10
net.ipv4.tcp_keepalive_probes = 20
net.ipv4.tcp_keepalive_intvl = 30

연결이 맺어진 뒤 10초(timeout) 동안 기다립니다. 그러곤 해당 커넥션이 살아있는지 확인합니다. 살아있다면 연결을 유지하지만 응답이 없다면 30초(intvl) 뒤에 다시 살아있는지 확인합니다. 최대 20번(probes)까지 살아있는지 확인을 시도합니다.

TCP 레벨에서의 keep-alive 옵션은 데드컨넥션을 제거하는데 효과적입니다. 클라이언트에서 서버로 연결 종료(FIN) 요청을 보내지 않고 자체적으로 커넥션을 제거한다면 서버에선 이를 알 방법이 없습니다. 따라서 서버에선 해당 커넥션을 계속 들고있는 문제가 발생합니다.

2. 웹 서버 keep-alive

웹 서버를 이용하는 경우에는 웹 서버가 자체적으로 관리하는 keep-alive 옵션을 이용합니다. 웹 서버의 keep-alive를 이용하는 경우에는 TCP keep-alive의 속성을 무시합니다.

Apache 서버와 같은 요청당 하나의 스레드를 할당하는 블로킹 구조에서는 맺어진 소켓별로 서버의 max_threads(max_clients)가 늘어납니다.

Nginx와 같은 논블로킹 구조에서는 그렇지 않습니다.

Nginx 기준으로 keep-alive 옵션은 다음과 같습니다.

keepalive_time = 10s // 한 번 맺어진 연결을 10초간 유지
keepalive_max = 10 // 한 번 맺어진 연결을 통해 최대 10번의 요청 가능

그렇다면 HTTP keep-alive는?

HTTP는 웹 서버 통신이기 때문에 TCP keep-alive가 아닌 웹 서버의 keep-alive 속성을 따릅니다.

HTTP는 일반적으로 Connectionless 방식으로 매 요청마다 연결을 새롭게 맺습니다. 요청이 빈번하게 발생한다면 매번 연결을 새롭게 맺는 방식은 비효율적입니다.

그래서 HTTP는 keep-alive 헤더를 제공합니다. 이 헤더를 이용해 keep-alive를 이용할지 말지 선택할 수 있습니다.

HTTP 1.0 에서는 헤더에 keep-alive 옵션을 추가해줘야 동작합니다.

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

HTTP 1.1 부터는 keep-alive가 기본 값으로 설정되어 있습니다. 별도 설정 없이 Keep-alive 옵션을 이용 가능합니다.

다만, 서버측의 웹 서버에 keep-alive 설정이 켜 있는 경우에만 동작을 합니다. 서버측의 웹 서버에 keep-alive 옵션이 켜져있지 않다면, 동작하지 않습니다.

HTTP Client 주의 사항

HTTP Client 입장에서 주의해야할 사항이 있습니다.

서버측에선 커넥션을 종료했는데 클라이언트에서 해당 커넥션을 제거하지 않은 상황에 해당 커넥션을 다시 이용하려고 시도하는 경우 문제가 될 수 있습니다.

이것을 half-closed connection이라 부릅니다.

Apache HTTP Client를 이용하는 경우에는 NoHttpResponseException을 받을 수 있습니다.

Netty를 이용하는 경우에는 PrematureCloseException을 받을 수 있습니다.

이 것을 해결하기 위해서 클라이언트에서는 서버에 설정된 keepalive_time보다 짧게 connection의 evict time(life time)을 설정해주어야 합니다.

Apache HTTP Client Connection Pool을 이용하는 경우에는 evictIdleConnections 옵션을 통해 컨트롤 할 수 있습니다.

profile
🎧

0개의 댓글