이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- LB idle timeout이 WebSocket, SSE, long polling, gRPC 연결을 어떻게 끊는가?
- heartbeat, keepalive, reconnect backoff를 timeout 체인과 어떻게 맞춰야 하는가?
- 장기 연결 장애를 사용자 네트워크 문제와 인프라 설정 문제로 어떻게 분리하는가?
개요
Idle timeout은 일정 시간 동안 데이터가 흐르지 않는 연결을 닫는 설정이다. REST API에서는 잘 드러나지 않지만 WebSocket, SSE, long polling, gRPC streaming에서는 사용자 경험을 직접 결정한다. 가장 짧은 timeout이 실제 연결 수명을 결정한다.
- LB, reverse proxy, app server, client SDK가 각각 timeout을 가진다.
- heartbeat가 idle timeout보다 길면 정상 연결도 끊긴다.
- mobile network 전환과 NAT idle timeout은 장기 연결을 더 불안정하게 만든다.
- 재연결 전략이 없으면 짧은 네트워크 흔들림이 사용자 기능 중단이 된다.
원리
장기 연결 경로는 다음 timeout chain을 가진다.
Client
-> Mobile carrier / NAT timeout
-> CDN / LB idle timeout
-> Reverse proxy read timeout
-> App server idle timeout
-> Application heartbeat연결이 60초마다 끊긴다면 어떤 계층의 기본 idle timeout이 60초인지 확인한다. 끊긴 간격이 일정하면 인프라 timeout, 불규칙하면 client network나 app backpressure 가능성이 커진다.
연결 유형별 판단
| 유형 | 주의점 |
|---|---|
| WebSocket | upgrade header, idle timeout, ping/pong |
| SSE | response buffering off, 주기적 comment heartbeat |
| Long Polling | request timeout과 client retry |
| gRPC Streaming | HTTP/2, keepalive, LB 지원 여부 |
| File Download | slow client와 send timeout |
설정 예시
WebSocket proxy 예시다.
location /ws/ {
proxy_pass http://app_upstream;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 1h;
}SSE는 buffering을 끄고 heartbeat를 보낸다.
location /events/ {
proxy_pass http://app_upstream;
proxy_buffering off;
proxy_read_timeout 1h;
}SSE heartbeat 예시다.
: heartbeat
data: {"type":"message","id":"m-1"}
코드와 명령으로 확인하기
SSE가 buffering 없이 주기적으로 오는지 확인한다.
curl -N https://api.example.com/eventsWebSocket은 전용 client로 연결 시간을 본다.
npx wscat -c wss://api.example.com/ws운영에서 Node 도구 사용이 어렵다면 브라우저 DevTools Network의 WS/SSE timing과 close code를 저장한다.
인프라 협업 포인트
- LB idle timeout, proxy read timeout, app heartbeat 주기를 같은 표로 맞춘다.
- 장기 연결 endpoint는 일반 REST target group과 분리할지 검토한다.
- connection 수가 많아지면 LB, proxy, app의 file descriptor, memory, thread/event loop 사용량을 함께 본다.
- 모바일 앱은 foreground/background 전환, 네트워크 전환, reconnect backoff 정책을 앱 팀과 맞춘다.
실전 팁
- heartbeat 주기는 idle timeout보다 충분히 짧게 둔다. 예를 들어 timeout 60초라면 20~30초 heartbeat를 검토한다.
- reconnect는 즉시 무한 재시도하지 말고 exponential backoff와 jitter를 둔다.
- 장기 연결은 배포 draining에 취약하다. 배포 중 연결 종료와 재연결 UX를 설계한다.
- gRPC는 HTTP/2 end-to-end 지원과 ALPN, proxy idle timeout을 같이 확인한다.
- 개인 프로젝트에서는 WebSocket보다 SSE가 운영상 단순한 경우가 많다. 양방향이 꼭 필요한지 먼저 묻는다.
위험 신호!
- SSE endpoint에 proxy buffering이 켜져 있다.
- WebSocket close code와 끊긴 주기를 수집하지 않는다.
- LB idle timeout보다 heartbeat 주기가 길다.
- reconnect storm이 장애 중 origin을 더 압박한다.
확인 질문
확인 질문
- 일정한 간격으로 장기 연결이 끊기면 무엇을 의심해야 하는가?
- LB, proxy, app server, NAT 중 하나의 idle timeout 기본값을 의심해야 한다.
- SSE에서
curl -N이 유용한 이유는 무엇인가?
- buffering 없이 이벤트가 즉시 흘러오는지 확인할 수 있기 때문이다.
- reconnect backoff가 필요한 이유는 무엇인가?
- 장애나 배포 중 많은 client가 동시에 재연결해 서버를 더 압박하는 상황을 줄이기 위해서다.