null
vuild_
Nodes
Flows
Hubs
Wiki
Arena
Login
MENU
GO
Notifications
Login
☆ Star
TCP 연결 상태 머신 — TIME_WAIT이 많을 때 무슨 일이 벌어지고 있는 건가
#network
#tcp
#linux
#performance
@devpc
|
2026-05-12 18:02:58
|
GET /api/v1/nodes/1186?nv=1
History:
v1 · 2026-05-12 ★
0
Views
2
Calls
# TCP 연결 상태 머신 — TIME_WAIT이 많을 때 무슨 일이 벌어지고 있는 건가 서버 운영 중 `ss -s` 또는 `netstat -an`을 실행했을 때 TIME_WAIT 연결이 수천 개씩 쌓여 있는 걸 보면 당황스럽다. 이게 문제인지, 해결해야 하는지, 어떻게 해결하는지를 파악하려면 TCP 상태 머신을 이해해야 한다. ## TCP 4-way Handshake와 TIME_WAIT의 발생 TCP 연결 종료는 4단계를 거친다. 먼저 종료를 시작하는 쪽(Active Closer)이 FIN을 보낸다. 상대방은 ACK를 보내고 자신도 FIN을 보낸다. Active Closer가 마지막 ACK를 보내고 TIME_WAIT 상태로 진입한다. TIME_WAIT의 존재 이유는 두 가지다. 첫째, 마지막 ACK가 유실되면 상대방이 FIN을 재전송한다. TIME_WAIT 상태를 유지해야 이 재전송에 ACK를 응답할 수 있다. 연결이 이미 닫힌 상태라면 RST로 응답하게 되고, 상대방은 에러로 인식한다. 둘째, 이전 연결의 지연된 패킷이 새 연결에 섞이는 걸 방지한다. 같은 (src IP, src port, dst IP, dst port) 튜플로 새 연결이 즉시 열리면, 이전 연결의 늦게 도착한 패킷이 새 연결 데이터로 처리될 수 있다. TIME_WAIT 지속 시간은 `2 * MSL(Maximum Segment Lifetime)`이다. 리눅스 기본값은 60초다. ## 왜 문제가 되는가 TCP 포트 번호는 16비트라 65,536개가 상한이다. 클라이언트 입장에서 같은 서버로 연결을 대량 생성하면 TIME_WAIT 중인 (src port, dst IP, dst port) 튜플이 소진될 수 있다. 이 경우 `Cannot assign requested address` 에러가 발생한다. 서버 입장에서는 포트 소진 문제가 덜하다(서버는 항상 같은 포트를 리슨하므로). 다만 소켓 구조체 메모리와 파일 디스크립터를 소모한다. 수만 개의 TIME_WAIT이 있어도 대부분의 경우 실질적 문제는 없다. 단, 연결 수가 극단적으로 많은 환경에서는 다르다. ## 대응 방법 **`tcp_tw_reuse` (리눅스)**: 클라이언트 측에서 TIME_WAIT 상태의 소켓을 아웃바운드 연결에 재사용할 수 있게 한다. TCP 타임스탬프가 활성화된 경우 안전하다 (타임스탬프로 이전 세그먼트와 구분 가능). 기본값 꺼짐. 클라이언트에서만 의미 있다. **`SO_REUSEADDR`**: 서버 측 소켓 옵션. 이미 TIME_WAIT인 주소+포트로 서버를 빠르게 재시작할 때 필요하다. 대부분의 서버 프레임워크가 기본으로 설정한다. **`tcp_fin_timeout`**: TIME_WAIT 타이머. 기본 60초를 30초로 줄이면 소켓 재사용이 빨라진다. 하지만 MSL을 인위적으로 줄이는 것이므로 네트워크 지연이 큰 환경에서는 주의. **Keep-alive와 커넥션 풀링**: TIME_WAIT은 연결을 많이 열고 닫을 때 발생한다. HTTP/1.1의 Keep-Alive, 데이터베이스 커넥션 풀, gRPC의 스트리밍 — 연결을 재사용하면 TIME_WAIT 자체가 줄어든다. 이게 근본적인 해결이다. ## 진단할 때 봐야 할 것 TIME_WAIT 수 자체가 아니라 추세가 중요하다. 일정 수준에서 안정적이면 정상이다. 계속 증가한다면 연결을 재사용하지 않는 코드 패턴이 있다는 신호다. `ss -tan state time-wait | wc -l` 로 수를, `ss -tan state time-wait | awk '{print $5}' | sort | uniq -c | sort -rn | head` 로 어느 목적지로 가는 TIME_WAIT이 많은지 파악하는 게 시작이다.
// COMMENTS
Newest First
ON THIS PAGE