-
HTTP Stateless와 Keep-Alive, 세션과 JWTCS/네트워크 2026. 7. 13. 21:33
HTTP의 Stateless는 요청 사이의 애플리케이션 문맥을 자동으로 기억하지 않는다는 뜻입니다. Keep-Alive는 여러 요청에서 TCP 연결을 재사용합니다. 둘은 서로 다른 계층의 개념입니다.
TCP가 기억하는 정보와 백엔드 애플리케이션이 기억할 정보는 다릅니다.
TCP는 양 끝의 IP와 포트, Sequence·ACK 번호, 송수신 버퍼와 윈도 등 바이트 전달에 필요한 연결 상태를 관리합니다. 반면 HTTP 요청을 보낸 사용자가 누구인지, 장바구니에 무엇을 담았는지, 이전 요청에서 어떤 비즈니스 로직을 실행했는지는 알지 못합니다.
Keep-Alive로 같은 TCP 연결을 재사용해도 로그인 상태가 저절로 이어지지는 않습니다. 서버가 사용자를 식별하려면 세션 ID나 JWT 같은 인증 정보를 각 HTTP 요청에 담아야 합니다.
Stateless는 연결을 끊는다는 뜻이 아니다
HTTP가 Stateless라는 말은 다음 요청을 처리할 때 서버가 이전 요청의 애플리케이션 문맥을 반드시 보관할 필요는 없다는 뜻입니다. 서버가 처리하는 데 필요한 정보는 각 요청에 들어 있어야 합니다.
Stateless를 매 요청마다 TCP 연결을 끊는다는 의미로 이해하면 안 됩니다. HTTP/1.1의 Keep-Alive는 한 번 맺은 TCP 연결을 여러 요청과 응답에서 재사용합니다. 연결을 새로 만드는 비용을 줄이는 전송 방식일 뿐, 로그인 사용자나 장바구니 같은 상태를 자동으로 전달하지는 않습니다.
HTTP 상태와 TCP 연결 상태는 다르다
TCP 연결은 일반적으로 출발지 IP·포트와 목적지 IP·포트의 4-tuple로 구분합니다. 연결이 만들어지면 양 끝은 Sequence·ACK 번호, 송수신 버퍼, 재전송 타이머, 흐름 제어와 혼잡 제어에 필요한 값 등을 관리합니다.
이런 상태는 바이트를 신뢰성 있게 전달하기 위한 것입니다. TCP는 현재 연결의 사용자가 로그인했는지, 어떤 권한을 가졌는지 알지 못합니다.
흐름 제어와 혼잡 제어도 구분해야 합니다.
- rwnd: 수신자가 자신의 버퍼 여유 공간을 송신자에게 알리는 수신 윈도입니다. 느린 수신자가 감당할 수 있는 범위로 전송량을 제한합니다.
- cwnd: 송신자가 네트워크의 혼잡 신호를 보고 관리하는 혼잡 윈도입니다. 네트워크에 지나치게 많은 데이터를 보내지 않도록 전송량을 제한합니다.
- 송신 측의 미확인 전송량은 대략 min(rwnd, cwnd)를 넘지 않도록 제한됩니다.
수신자가 rwnd를 보내면 송신자는 이 값을 참고합니다.
Stateless HTTP에서 로그인 상태를 전달하는 방법
세션 방식은 로그인에 성공하면 서버가 임의의 세션 ID를 만들고, 브라우저는 이를 보통 쿠키에 저장합니다. 다음 요청부터 브라우저가 세션 ID를 보내면 서버는 메모리나 Redis에서 세션 데이터를 조회해 사용자를 식별합니다.
브라우저 쿠키: session_id=abc123 서버 또는 Redis: abc123 → 사용자 ID와 권한JWT 방식에서는 서버가 사용자 정보와 만료 시간 등의 Claim을 담은 토큰에 서명합니다. 클라이언트는 JWT를 쿠키나 Authorization: Bearer 헤더로 보내고, 서버는 서명과 만료 시간을 검증해 인증 객체를 만듭니다.
클라이언트: 서명된 JWT 보관 서버: JWT 서명·만료 시간·Claim 검증세션 ID는 일반적으로 JWT가 아니라 의미를 추측하기 어려운 임의의 값입니다. 쿠키는 정보를 저장하고 전송하는 수단이며 JWT는 토큰 형식입니다. 따라서 JWT를 쿠키에 담아 사용할 수도 있습니다.
서버가 여러 대일 때 세션을 어떻게 유지할까
로드밸런서 뒤에 서버 A와 B가 있고 A의 JVM 메모리에만 세션을 저장했다고 가정해 보겠습니다. A에서 로그인한 사용자의 다음 요청이 B로 가면 B는 세션을 찾지 못해 사용자를 미인증 상태로 판단합니다.
이 문제를 해결하는 방식은 세 가지입니다.
Sticky Session
로드밸런서가 같은 사용자의 요청을 계속 같은 서버로 보냅니다. 로컬 메모리 세션을 그대로 활용할 수 있지만 특정 서버로 부하가 쏠릴 수 있습니다. 서버가 죽으면 그 서버의 세션도 함께 사라질 수 있다는 한계도 있습니다.
공용 Redis 세션
모든 애플리케이션 서버가 같은 Redis에서 세션을 조회합니다. 어느 서버가 요청을 받아도 인증할 수 있어 수평 확장에 유리합니다. 다만 Redis가 인증 경로의 공용 의존성이자 병목이 되므로 복제, 장애조치, 타임아웃과 가용성을 함께 설계해야 합니다.
JWT
각 서버가 토큰의 서명을 검증하므로 사용자별 세션을 공유하지 않고 요청을 처리합니다. 애플리케이션 서버를 늘리기는 쉽지만 토큰 탈취, 강제 로그아웃, 권한 변경의 즉시 반영, Refresh Token 관리가 까다롭습니다.
JWT가 언제나 세션보다 가벼운 것은 아닙니다. 세션 저장소 조회를 줄이는 대신 JWT는 세션 ID보다 크고, 요청마다 서명을 검증해야 합니다. 저장소 의존성을 줄이는 대신 전송 크기와 폐기 정책의 복잡성을 떠안는 셈입니다.
인증 실패와 인증 인프라 장애를 구분해야 한다
상태 코드는 클라이언트 자격 증명의 문제인지, 서버 의존성의 문제인지에 따라 달라집니다.
- 자격 증명이 없거나 유효하지 않음: 401 Unauthorized
- 인증은 됐지만 필요한 권한이 없음: 403 Forbidden
- 세션 쿠키는 있지만 Redis 장애로 검증할 수 없음: 서버 의존성 장애이므로 503 Service Unavailable을 고려합니다.
- 서명이 정상인 Access Token이 만료됨: 리소스 서버는 401을 반환하고, 클라이언트는 유효한 Refresh Token으로 재발급을 요청할 수 있습니다.
- JWT 서명이 일치하지 않음: 변조된 자격 증명으로 보고 401을 반환합니다. 검증되지 않은 토큰의 Claim을 신뢰해 관련 계정을 임의로 조작하면 안 됩니다.
Redis가 응답하지 않는다고 사용자를 다시 로그인시키는 건 해결책이 아닙니다. 새 로그인 세션도 Redis에 저장할 수 없기 때문입니다. 그렇다고 인증을 우회하면 보안 문제가 생깁니다. 기본적으로 Fail Closed 정책을 적용하고 저장소의 가용성을 복구해야 합니다.
Refresh Token도 모든 JWT 오류를 해결하지는 못합니다. 정상적으로 만료된 Access Token을 갱신할 때 사용하는 수단입니다. Access Token의 서명이 잘못됐거나 Refresh Token도 만료·위조됐다면 인증을 거부하거나 다시 로그인해야 합니다.
결론
HTTP Stateless와 TCP Keep-Alive는 모순되지 않습니다. Keep-Alive는 전송 계층의 연결을 재사용하고, Stateless는 애플리케이션 요청 사이의 문맥을 자동으로 보존하지 않습니다.
백엔드가 로그인 상태를 제공하려면 세션이나 JWT로 요청마다 사용자를 식별해야 합니다. 서버가 여러 대라면 Sticky Session, 공용 Redis, JWT의 장애 특성과 확장성을 비교해야 합니다. 인증 실패와 인증 시스템 장애를 구분해야 401, 403, 503도 상황에 맞게 선택할 수 있습니다.
요약
- Stateless는 애플리케이션 요청 문맥에 관한 말이지 TCP 연결 수명에 관한 말이 아닙니다.
- TCP 연결 상태와 로그인·장바구니 같은 비즈니스 상태를 구분합니다.
- 쿠키는 전달 수단이고 세션 ID와 JWT는 사용자를 식별하는 서로 다른 방식입니다.
- 분산 환경에서는 상태의 저장 위치가 확장성과 장애 범위를 결정합니다.
- 인증 실패와 인증 인프라 장애를 구분해 상태 코드를 선택합니다.
'CS > 네트워크' 카테고리의 다른 글
TCP 3-Way Handshake (0) 2026.07.24 주소창에 도메인을 입력하면, IP는 어디서 올까? DNS 조회의 전체 흐름 (0) 2026.07.23 HTTP HOL Blocking에서 QUIC Stream까지 (0) 2026.06.29