서버를 운영하다가 연결은 되는데 응답이 없는 상황 겪어보셨나요? 사실 저는 이럴 때 정말 난감하고 짜증나더라고요.
TCP 레벨에서는 3-way 핸드쉐이크가 정상적으로 연결되고, 포트도 열려 있고 패킷도 정상적으로 작동해요.
그런데 정작 애플리케이션에서는 타임아웃이 발생하는데 그 이유는 왜 일어날까요?
타임아웃이 발생하는 이유는 네트워크에서 오류가 난 것이 아니라, 전송이랑 애플리케이션 사이의 차이때문에 발생해요.
오늘은 그 이유와 원인에 대해서 자세히 알아볼게요!
서버 애플리케이션 처리 지연
서버 애플리케이션 처리 지연때문에 자주 발생하긴 하는데요.
자주 발생해서 큰 문제가 아니라고 생각할 수 있지만 그렇게 생각하시면 안 돼요.
TCP 연결이 성립됐다는 건 통로가 열렸다는 의미이지 실제로 요청을 처리할 준비가 됐다는 뜻은 아니에요!
- 요청 큐가 가득 찬 상태(백로그 초과)
- 스레드 풀 또는 워커 부족
- 내부 로직 처리 지연 (DB, 외부 API 호출)
백로그 초과, 스레드 풀 또는 워커 부족, 내부 로직 처리 지연 같은 이유 때문에 처리 지연이 발생하니 알아두는 게 좋겠죠?
확인할것
- 애플리케이션 로그에서 요청 처리 시간 확인
- 큐 적체 여부 (Nginx → upstream 지연)
- 스레드/워커 상태
Reverse Proxy와 Upstream 간 타임아웃
Nginx, HAProxy 같은 리버스 프록시에서는 클라이언트 → 프록시 → 백엔드 구조로 요청돼요.
이때 프록시와 백엔드 간 타임아웃 설정이 충족 시간을 못 채우고 짧다면 TCP 연결은 유지되지만 응답이 끝까지 가지 못하고 끊겨요.
대표적인 설정
- proxy_connect_timeout
- proxy_read_timeout
- proxy_send_timeout
문제 상황
- 백엔드 처리 시간 > proxy_read_timeout → 클라이언트에 타임아웃 발생
TCP Keepalive와 Idle Timeout 일치하지 않는 경우
네트워크 장비나 클라우드에서는 유휴 연결을 일정 시간이 지나면 서버 안에서 강제로 끊는 경우가 정말 많아요.
여기서 가장 큰 문제는 애플리케이션이 이 연결 되어있는 것을 유효하다고 생각하고 데이터를 보내는 순간 문제가 발생해요.
- 서버: 연결 유지 중이라고 판단
- 중간 장비: 이미 연결 종료
이렇게 되면 결과적으로 패킷이 제대로 전달이 안 되어서 타임아웃이 된답니다!
해결방법
- TCP keepalive 설정 조정
- 로드밸런서 idle timeout 확인
- 애플리케이션 커넥션 재사용 정책 점검
커널 레벨 큐 병목현상
TCP 연결은 성공적으로 잘 됐지만 애플리케이션이 아직 accept() 하지 못한 상태일 수 있어요.
이럴 때는 이런 상황이랍니다!
- 커널 레벨에서는 연결 OK
- 하지만 애플리케이션은 아직 요청을 처리하지 못함
특히 트래픽이 순간적으로 확 몰릴 때 병목현상이 생겨요.
확인방법
- ss -lnt
- netstat -s
이 두가지로 확인 할 수 있으니 커널 레벨 큐 병목현상인 것 같으면 확인 한 번 해보세요!
관련 파라미터
- net.core.somaxconn
- net.ipv4.tcp_max_syn_backlog
MTU / 패킷 분할 문제
TCP 연결에는 문제가 없지만 실제 데이터 전송 과정에서 패킷이 손실되거나 분할되면 응답 지연이 발생할 수도 있어요.
특히 VPN, 터널링, 컨테이너 네트워크 환경에서 자주 발생해요.
특징
- 작은 요청에는 정상으로 뜸
- 하지만 큰 응답이면? 타임아웃 발생
애플리케이션 레벨 프로토콜 오류
HTTP, gRPC, DB 프로토콜 등에서 요청은 잘 전달 됐지만 응답 포맷이나 상태가 깨지면 클라이언트가 자동으로 타임아웃 됩니다!
예시를 보여드리자면,
- Content-Length 불일치
- 응답 스트림 중단
- 프로토콜 핸드셰이크 실패
마무리
TCP 연결이 정상이라는 것은 네트워크가 살아있다는 최소 조건이에요.
실제 서비스 응답은 밑에 레이어들이 모두 정상적으로 되어 있어야 응답이 돼요.
- 커널 네트워크 큐
- 애플리케이션 처리 구조
- 프록시 및 로드밸런서
- 프로토콜 레벨 처리
타임아웃이 났을 때는 에러가 하나만 났을 거라고 확신하는 것이 아니라 패킷 → 커널 → 애플리케이션 → 프록시까지 전체적으로 확인하셔야 합니다! 전체적으로 확인 하지 않는다면 원인을 찾기 너무 어려워져요..
오늘도 긴 글 읽어주셔서 감사합니다. 다음에도 도움이 될 만한 정보 가져오겠습니다!!