Keep Alive
HTTP를 보다가 Keep Alive가 궁금해졌다. 연결을 유지시킨다는 것만 알고 있어서 찾아봤다.
Keep Alive는 HTTP Keep Alive와 TCP Keep Alive 두 가지가 존재한다.
왜 두 가지가 존재하나
TCP는 전송 계층(L4), HTTP는 애플리케이션 계층(L7)으로 서로 다른 계층에 속한다.
계층표가 궁금하다면 아래 글로
TCP
TCP는 4계층에 속한다. OSI 계층 TCP/IP 계층 7 Application Application Application 6 Presentation FTP Telnet HTTP DNS RTSP etc.. 5 Session 4 Transport Transport TCP UDP ICMP, IGMP 3 Network Network (Internet) IPv4 / IPv6 2 Data Link Network Interf
dodo5517.tistory.com
HTTP Keep-Alive ← 애플리케이션 정책
----------------
TCP Keep-Alive ← OS 커널 기능
----------------
IP
둘은 목적도, 동작 주체도 다르기 때문에 따로 존재하고, 동시에 사용하는 것도 가능하다.
- HTTP Keep-Alive = 연결 재사용 정책: 이 TCP 연결 써도 되나?
- TCP Keep-Alive = 연결 생존 감지 메커니즘: 연결 자체가 살아있나?
HTTP Keep-Alive
원래 HTTP/1.0은 요청 하나 보내고 → 응답 받으면 → TCP 연결을 끊었다. 그래서 요청마다 TCP 3-way handshake를 새로 해야 했고, 이게 오버헤드였다.
HTTP Keep-Alive를 쓰면 응답 후에도 TCP 연결을 유지해서 다음 요청에 재사용한다.
Connection: keep-alive
Keep-Alive: timeout=5, max=100
timeout: 몇 초 동안 요청이 없으면 끊을지max: 최대 몇 번까지 재사용할지
HTTP/1.1부터는 Keep-Alive가 기본값이라 명시하지 않아도 유지된다. 끊고 싶을 때 Connection: close를 쓴다.
단, HTTP/1.1에서는 하나의 TCP 연결에서 요청을 순차적으로 처리하기 때문에 이전 요청/응답이 완료되기 전까지 같은 연결로 새 요청을 보낼 수 없다(HOL Blocking). HTTP/2부터는 멀티플렉싱으로 이 문제가 해결되어 하나의 TCP 연결에서 여러 요청을 동시에 처리할 수 있다.
TCP Keep-Alive
OS 커널이 데이터 전송이 없는 유휴 연결에 대해 일정 시간이 지나면 빈 ACK 패킷(probe)을 보내서 상대방이 살아있는지 확인한다. 응답이 없으면 몇 번 더 재시도하고, 그래도 없으면 연결을 끊는다.
Linux 기본값 기준:
| 파라미터 | 기본값 | 의미 |
|---|---|---|
tcp_keepalive_time |
7200초 (2시간) | 유휴 상태가 이 시간 지나면 probe 시작 |
tcp_keepalive_intvl |
75초 | probe 재시도 간격 |
tcp_keepalive_probes |
9회 | 이 횟수만큼 재시도 후 연결 종료 |
이게 필요한 이유는 중간에 NAT 장비나 방화벽이 일정 시간 동안 패킷이 없으면 해당 세션을 테이블에서 지워버리기 때문이다. TCP Keep-Alive probe가 이걸 방지한다.
새 요청을 보낼 때 판단 흐름
새 HTTP 요청을 보내려 할 때
│
▼
TCP 연결이 살아있나? ──No──→ 새 TCP 연결 수립 (3-way handshake)
│ Yes
▼
HTTP에서 재사용 가능한가? ──No──→ 새 TCP 연결 수립
(keep-alive이고, timeout/max 안 넘었나?)
│ Yes
▼
기존 연결 재사용 ✓
정리
| HTTP Keep-Alive | TCP Keep-Alive | |
|---|---|---|
| 계층 | 애플리케이션 (L7) | 전송 (L4), OS 커널 |
| 목적 | TCP 연결 재사용 (handshake 비용 절감) | 연결 생존 여부 감지 |
| 동작 주체 | 브라우저 / 웹서버 | OS |
| 제어 | Connection, Keep-Alive 헤더 |
setsockopt() 또는 커널 파라미터 |