서버 운영하다 보면 netstat이나 ss 명령어 확인했을 때 TIME WAIT 상태의 소켓이 너무 많이 생기는 상황이 무조건 생겨요.
일정 수준 정도는 괜찮지만 너무 많이 생기면 포트 고갈이나 연결이 지연되는 등 서버에 오류가 발생해요.
이번 글에서는 TIME WAIT이 왜 발생하는지와 어떨 때 비정상적으로 생기는지 정리해봤어요!
TIME WAIT 필요한가
TIME WAIT은 TCP 연결 종료할 때 마지막 패킷의 신뢰성과 지연 패킷 처리를 보장하기 위해서 존재합니다!
즉, TIME WAIT을 안 좋다고 생각해서 극단적으로 줄이려고 하거나 없애려고 하면 나중에 더 큰 문제가 생길 수 있어요.
클라이언트 역할
TIME WAIT은 기본적으로 연결을 먼저 종료한 곳에 생겨요.
다 같은 서버라고 해서 항상 TIME WAIT이 생기는 게 아니에요!
- 외부 API 호출이 많은 서버
- DB 커넥션을 짧게 반복해서 생성
- 내부 마이크로서비스 간 호출이 잦은 경우
이 3가지와 같은 상황들이 생길 때 생길 확률이 높답니다.
특히 HTTP keepalive를 사용하지 않는 곳에서는 요청을 할 때마다 새로운 TCP 연결이 만들어지면서 TIME WAIT이 계속 생성이 돼요.
짧은 커넥션 패턴
다음과 같은 트래픽 패턴은 TIME_WAIT 폭증의 대표적인 원인이에요.
- 초당 수천 건 이상의 짧은 요청
- 연결 생성 → 요청 → 즉시 종료 구조
- 커넥션 풀 없이 매 요청마다 새 연결 생성
위에 설명드린 3가지와 같은 패턴은 TIME WAIT이 순간적으로 많이 생기는 가장 흔한 원인이니까 알아두시면 좋아요.
에페머럴 포트 부족
TIME WAIT이 일정 수준으로 생기게 되면 에페머럴 포트가 가장 먼저 부족해질 수 있어요.
리눅스는 기본적으로 대략 28000개 정도의 ephemeral port 범위를 사용해요.
TIME WAIT소켓이 이 범위를 초과하게 되면 연결을 새롭게 하지 못 하게 돼요.
확인 방법
- cat /proc/sys/net/ipv4/ip_local_port_range
커널 튜닝 이용하기
무조건 TIME WAIT을 줄이려고 하는 게 아니라 연결 구조이랑 커널 설정을 함께 조정하는 것이 좋아요!
포트 범위 확장
- sysctl -w net.ipv4.ip_local_port_range=”1024 65535″
사용 가능한 포트 수를 늘려서 부족해지는 것을 막는 게 좋습니당.
TIME WAIT 재사용
- sysctl -w net.ipv4.tcp_tw_reuse=1
TIME WAIT 소켓을 재사용하는 방법도 있어요!
하지만 NAT 환경이나 외부 통신에서는 생각하지 못한 변수가 생길 수 있기에 TIME WAIT을 재사용하기 전에는 신중하게 생각하고 사용하는 것이 좋습니다.
TIME WAIT 감소 설정
옛날에는 tcp_tw_recycle이 사용됐지만 지금은 NAT 환경에서 오류가 계속 발생해서 대부분의 시스템에서 없어졌어요.
하지만 이 방법은 개인적으로 리스크가 있다고 생각해서 추천드리지 않는 방법이에요! 그냥 이런 방법도 있구나 라고 생각하시면 좋을 것 같아요.
가장 기본적인 해결 방법
커널 튜닝보다 더 중요한 건 애플리케이션 구조를 개선하는 것입니다!
권장드리는것
- HTTP Keep-Alive 활성화
- DB 커넥션 풀 사용
- 연결 재사용 구조 설계
- gRPC 등 장기 연결 기반 프로토콜 고려
이 4가지 방법이 가장 근본적인 해결 방법이에요! 이 해결 방법을 사용하는 걸 추천드립니다.
마무리
TIME WAIT 소켓이 계속 생기는 것은 리눅스 튜닝 문제가 아니라 트래픽 패턴과 애플리케이션 구조때문에 생기는 거에요!
- 무조건 TIME_WAIT 줄이기
- 커널 옵션만으로 해결하려는 시도
무조건 TIME WAIT을 줄여야지, 나는 커널 옵션으로만 해결할 거야 라고 하는 건 잘못된 방식인 걸 알아두세요.
밑에 4가지는 올바르게 해결하는 방법이에요!
- 연결 생성 패턴 분석
- 포트 사용량 확인
- 커널 설정 보완
- 애플리케이션 구조 개선
이렇게 해결하려고 하면 시스템의 안정성과 성능 둘 다 가질 수 있답니다!
오늘은 조금 어려운 문제로 글을 다뤄봤는데, 다음에는 조금 더 쉬운 주제로 여러분들에게 설명드리겠습니다. 감사합니다!