HTTP Keep-Alive
HTTP/1.1부터는 기본적으로 Keep-Alive가 활성화되어 있다.
이는 하나의 TCP 커넥션을 여러 HTTP 요청/응답에 재사용하는 방식이다.
클라이언트가 Connection: keep-alive 헤더를 요청에 포함시키면,
서버는 해당 커넥션을 일정 시간 동안 유지한 뒤, 다음 요청에도 재사용할 수 있게 만든다.
소켓이란?
- 자바에서
Socket 객체는 내부적으로 FileDescriptor를 포함하며, 이는 OS 레벨의 TCP 소켓과 연결되어 있다.
- 하나의 소켓은 TCP 커넥션 하나에 해당하며, 클라이언트의 IP:PORT와 서버의 IP:PORT 쌍으로 식별된다.
- 커넥션이 닫히지 않는 한, 이 소켓은 계속해서 읽기/쓰기 작업에 사용될 수 있다.
소켓을 재사용할 수 있는 이유
TCP 커넥션이 종료되지 않았으니까
- 소켓을 재사용할 수 있다는 말은, 커넥션을 닫지 않고 유지하고 있기 때문이다.
keep-alive는 TCP 커넥션을 끊지 않으므로, 동일한 소켓을 계속 활용할 수 있다.
소켓을 커넥션 풀로 관리
- 내 WAS에서는 연결된 소켓을
ConnectionContext, ConnectionManager로 관리한다.
- 응답 후 소켓을 닫지 않고, 일정 시간 동안 재사용 가능한 상태로 유지한다.
OS는 같은 커넥션에 대해 식별자를 유지한다
- 커널은 하나의 TCP 커넥션을
IP:PORT 쌍으로 식별하고 관리한다.
- 해당 소켓이
ESTABLISHED 상태인 동안에는 재사용이 가능하다.
HTTP는 요청 단위로 메시지를 파싱하므로, 연결 유지와는 무관하다.
- HTTP는 stateless한 프로토콜이지만, TCP 커넥션이 살아 있는 한 여러 개의 HTTP 요청을 순차적으로 처리할 수 있다.
- 클라이언트와 서버는 메시지 단위로 통신하고, 연결 자체는 재사용된다.
소켓 재사용을 구현할 때 고려할 것
유휴 커넥션 관리
- 요청이 오지 않는 커넥션을 무한히 열어두면 리소스 낭비가 발생한다.
- 일정 시간(
timeout) 이후에는 연결을 닫아야 한다.
다중 요청 구분
- Keep-Alive를 사용할 경우 여러 요청이 같은 소켓으로 들어온다.
- 각 요청/응답의 경계를 정확히 파싱하지 않으면 메시지가 섞이거나 오염될 수 있다.
Connection 헤더 처리
- 클라이언트가
Connection: close를 명시하면, 해당 응답 이후에는 소켓을 닫아야 한다.
- 서버도 필요 시
Connection: close를 응답에 명시하여 커넥션 종료를 유도할 수 있다.
결론.
요청에 맞는 소켓을 재사용할 수 있는 이유는 커넥션을 끊지 않고 유지하기 때문이고, 해당 커넥션은 OS 에서 열린 상태로 관리되기 때문이다.
소켓 재사용을 제대로 하려면, 단순히 재사용 여부를 넘어서 연결 상태 관리, 요청 경계 파악, 리소스 해제까지 신경 써야 한다.
todo
- 여러 요청이 동일한 소켓을 통해 들어왔을 때, 요청/응답 경계를 정확히 파싱하는 로직 보완
- 테스트 환경에서
keep-Alive 요청을 다양한 방식으로 보내보며 확인 뭐가 있을까...