TCP 패킷 분석과 Retransmission, TIME_WAIT, CLOSE_WAIT 완벽 이해
TCP 패킷 분석과 Retransmission, TIME_WAIT, CLOSE_WAIT 완벽 이해
서버를 운영하다 보면 다음과 같은 상황을 경험할 수 있다.
- 서버의 TCP 연결 수가 갑자기 증가한다.
TIME_WAIT상태가 수천 개 이상 쌓인다.CLOSE_WAIT상태가 계속 증가한다.- 서비스는 실행 중인데 클라이언트 응답이 느리다.
- TCP 연결이 반복적으로 재전송된다.
- 서버의 CPU 사용률은 낮은데 네트워크 응답이 느리다.
ss에서는 연결이 보이지만 실제 데이터 전송이 원활하지 않다.
이러한 문제를 해결하려면 단순히 포트가 열려 있는지 확인하는 것만으로는 부족하다.
TCP가 데이터를 어떻게 추적하고, 손실을 어떻게 감지하며, 연결을 어떻게 종료하는지 이해해야 한다.
이번 편에서는 다음 순서로 학습한다.
TCP Sequence Number
↓
TCP ACK Number
↓
TCP Window Size와 Flow Control
↓
TCP Retransmission
↓
TCP 4-Way Termination
↓
TIME_WAIT와 CLOSE_WAIT
↓
Linux 명령어를 이용한 장애 분석
↓
tcpdump 패킷 분석
1. TCP는 데이터를 어떻게 추적하는가?
TCP는 데이터를 전송할 때 각 바이트의 위치를 추적한다.
이를 위해 사용하는 핵심 정보가 다음 두 가지다.
- Sequence Number
- Acknowledgment Number
이 두 값을 이해하면 TCP 패킷 분석의 상당 부분을 이해할 수 있다.
1-1. Sequence Number란?
Sequence Number는 TCP 데이터 스트림에서 해당 데이터가 시작하는 바이트의 위치를 나타낸다.
예를 들어 클라이언트가 서버에 3,000바이트의 데이터를 전송한다고 가정하자.
Client | | TCP Data: 3,000 bytes | v Server
TCP는 데이터를 여러 세그먼트로 나누어 전송할 수 있다.
Segment 1: 1,000 bytes Segment 2: 1,000 bytes Segment 3: 1,000 bytes
첫 번째 세그먼트의 Sequence Number가 1000이라면 개념적으로 다음과 같이 표현할 수 있다.
Segment 1 SEQ = 1000 Data = 1000 bytes Segment 2 SEQ = 2000 Data = 1000 bytes Segment 3 SEQ = 3000 Data = 1000 bytes
수신 측은 Sequence Number를 이용해 각 데이터가 스트림의 어느 위치에 해당하는지 판단한다.
단, 실제 TCP 연결에서는 초기 Sequence Number(ISN)가 임의의 값으로 선택되므로 위 숫자는 설명을 위한 예시다.
1-2. SYN과 FIN도 Sequence Number를 소비한다
여기서 중요한 특징이 있다.
TCP에서 SYN과 FIN은 각각 Sequence Number 공간에서 1을 소비한다.
따라서 SYN 패킷의 Sequence Number가 1000이라면 상대방은 다음 번호인 1001을 확인 대상으로 응답할 수 있다.
Client Server
SYN
SEQ = 1000
------------------------>
SYN + ACK
SEQ = 5000
ACK = 1001
<------------------------
ACK
SEQ = 1001
ACK = 5001
------------------------>
반면 ACK 플래그 자체는 Sequence Number를 소비하지 않는다.
TCP 데이터가 없는 일반적인 ACK는 별도의 데이터 바이트를 소비하지 않는다.
이 차이를 이해하면 tcpdump에서 SEQ와 ACK 값을 해석하기 쉬워진다.
2. ACK Number는 무엇을 의미하는가?
ACK Number는 수신 측이 다음에 받기를 기대하는 Sequence Number를 나타낸다.
예를 들어 서버가 다음과 같은 데이터를 받았다고 하자.
SEQ = 1000 Data Length = 1000 bytes
데이터가 정상적으로 수신되었다면 다음과 같이 ACK를 보낼 수 있다.
ACK = 2000
이는 다음과 같은 의미다.
1000부터 1999까지의 데이터 바이트를 받았으며 다음에는 2000부터의 데이터를 기대한다.
이것이 TCP의 누적 확인 응답(Cumulative Acknowledgment)이다.
2-1. 실제 데이터 전송 예시
Client Server
SEQ=1000
DATA=1000 bytes
------------------------>
ACK=2000
<------------------------
SEQ=2000
DATA=1000 bytes
------------------------>
ACK=3000
<------------------------
이 구조를 통해 송신 측은 어느 지점까지 데이터가 확인되었는지 추적할 수 있다.
2-2. ACK가 증가하지 않는다면?
다음과 같은 상황을 가정해 보자.
Client Server
SEQ=1000
DATA=1000
------------------------>
ACK=2000
<------------------------
SEQ=2000
DATA=1000
----X 패킷 손실
SEQ=3000
DATA=1000
------------------------>
ACK=2000
<------------------------
두 번째 데이터가 손실되었는데 세 번째 데이터가 도착하면, 수신 측은 누락된 데이터가 있는 지점의 ACK를 반복해서 보낼 수 있다.
이러한 반복 ACK와 선택적 확인 응답(SACK) 등의 정보는 TCP 손실 복구 과정에서 사용될 수 있다.
다만 ACK가 반복된다고 해서 반드시 네트워크 장비에 장애가 있다는 뜻은 아니다. 패킷 손실, 패킷 재정렬 등 여러 원인이 가능하다.
3. TCP Window Size와 Flow Control
TCP는 상대방이 데이터를 받을 수 있는 속도와 양을 고려해 데이터를 전송한다.
수신 측의 처리 능력을 고려하지 않고 데이터를 계속 보내면 수신 버퍼가 가득 찰 수 있기 때문이다.
이를 방지하기 위해 사용하는 기능이 흐름 제어(Flow Control)다.
3-1. Receive Window란?
TCP Header에는 Window Size 필드가 있다.
수신 측은 이 값을 이용해 송신 측에 자신이 현재 수신할 수 있는 데이터의 양을 알린다.
예를 들어 서버가 다음과 같이 광고한다고 가정하자.
Window = 65535
이는 TCP 흐름 제어 관점에서 수신 측이 광고하는 수신 가능 윈도우 크기를 나타낸다.
송신 측은 확인되지 않은 데이터의 양이 수신 측의 광고 윈도우를 초과하지 않도록 조절한다.
실제 유효 윈도우는 Window Scale 옵션 등에도 영향을 받는다.
3-2. 수신 버퍼가 부족한 경우
Client Server
DATA
------------------------>
Receive Buffer 증가
Window 감소
<------------------------
DATA 전송량 조절
수신 측이 처리할 데이터가 많아지면 광고 윈도우가 작아질 수 있다.
만약 다음과 같이 나타난다면 주의해서 살펴볼 필요가 있다.
Window = 32768 Window = 16384 Window = 4096 Window = 0
Window가 0이라는 것은 수신 측이 현재 새로운 데이터를 받을 수 있는 윈도우 공간이 없다고 광고한다는 뜻이다.
이 경우 송신 측은 Zero Window Probe 등의 메커니즘을 이용해 수신 가능 상태가 회복되었는지 확인할 수 있다.
단, Window가 작다는 이유만으로 장애라고 판단해서는 안 된다. 애플리케이션의 읽기 속도, 버퍼 사용량, 네트워크 상황 등을 함께 확인해야 한다.
3-3. Linux에서 Window Size 확인하기
다음 명령어로 TCP 연결 정보를 확인한다.
ss -tin
특정 연결을 확인하려면 다음과 같이 실행할 수 있다.
ss -tin dst 192.168.10.100
출력에는 다음과 같은 정보가 포함될 수 있다.
ESTAB 0 0 192.168.10.50:53124 192.168.10.100:443
cubic wscale:7,7
rto:204 rtt:2.5/0.5
snd_cwnd:10
bytes_sent:12000
bytes_acked:12000
출력 항목은 커널 버전과 연결 상태에 따라 달라진다.
주요 항목은 다음과 같다.
항목의미rtt왕복 지연 시간 추정치rto재전송 타임아웃 관련 값wscaleWindow Scale 관련 정보snd_cwnd송신 혼잡 윈도우bytes_sent전송한 바이트bytes_acked확인 응답을 받은 바이트
특히 snd_cwnd와 수신 측 광고 윈도우는 서로 다른 개념이다.
- 수신 윈도우(RWND): 수신 측이 받을 수 있는 양에 대한 제한
- 혼잡 윈도우(CWND): 네트워크 혼잡을 고려해 송신 측이 조절하는 전송량 제한
실제 전송량은 두 제한과 다른 TCP 상태에 영향을 받는다.
4. TCP Retransmission이란?
TCP는 데이터가 손실되었거나 정상적으로 확인되지 않았을 때 데이터를 재전송할 수 있다.
이를 Retransmission이라고 한다.
예를 들어 클라이언트가 서버에 데이터를 보낸다고 하자.
Client Server
DATA
------------------------>
네트워크에서 손실
클라이언트는 데이터가 정상적으로 전달되었는지 확인할 수 없다.
ACK가 돌아오지 않는다면 TCP는 손실 복구 절차를 수행한다.
대표적인 방식은 다음과 같다.
- 재전송 타임아웃(RTO)에 따른 재전송
- 중복 ACK 등을 이용한 손실 감지
- SACK 등의 정보를 이용한 선택적 재전송
TCP 구현과 네트워크 상황에 따라 구체적인 동작은 달라질 수 있다.
4-1. RTO 기반 재전송
Client Server
DATA
------------------------>
ACK 없음
RTO 만료
DATA 재전송
------------------------>
송신 측은 ACK를 기다리다가 재전송 타임아웃이 발생하면 필요한 데이터를 다시 전송할 수 있다.
RTO는 고정된 단일 값이 아니다. TCP는 측정된 RTT와 그 변동 등을 고려해 타임아웃을 계산한다.
4-2. tcpdump에서 재전송 확인하기
다음 명령어를 사용한다.
tcpdump -nn -i ens160 'tcp port 443'
예를 들어 다음과 비슷한 패킷이 반복해서 보인다고 가정하자.
192.168.10.50.53124 > 192.168.10.100.443: Flags [P.], seq 1001:1501, ack 5001 192.168.10.50.53124 > 192.168.10.100.443: Flags [P.], seq 1001:1501, ack 5001
동일한 Sequence 범위가 반복해서 나타난다면 재전송 가능성이 있다.
Wireshark에서는 분석 상황에 따라 다음과 같은 표시를 확인할 수 있다.
TCP Retransmission TCP Fast Retransmission TCP Dup ACK TCP Out-of-Order
단, 패킷 캡처의 중복, 패킷 재정렬, 캡처 위치 등에 따라서도 유사한 모습이 나타날 수 있다. 재전송 여부는 양방향 패킷과 ACK 흐름을 함께 살펴 판단해야 한다.
4-3. 재전송이 발생하는 주요 원인
원인설명네트워크 패킷 손실스위치, 라우터, 회선 등에서 패킷이 손실됨혼잡트래픽이 몰려 큐가 가득 차거나 패킷이 드롭됨무선 구간 문제무선 환경에서 패킷 손실이 발생함방화벽 또는 보안 장비정책이나 장비 상태에 따라 패킷이 드롭됨서버 과부하처리 지연이 발생해 응답이 늦어질 수 있음비대칭 경로요청과 응답이 서로 다른 경로를 통과함
재전송이 보인다고 해서 무조건 서버가 문제인 것은 아니다.
클라이언트, 서버, 중간 네트워크 구간 중 어디에서 손실이 발생하는지 확인해야 한다.
5. TCP 연결 종료 — 4-Way Termination
TCP 연결은 데이터를 주고받은 뒤 종료할 수 있다.
정상적인 연결 종료는 일반적으로 FIN과 ACK를 이용해 진행된다.
이를 4-Way Termination이라고 부른다.
Client Server | | |------------- FIN ------------>| | | |<------------ ACK -------------| | | |<------------ FIN -------------| | | |------------- ACK ------------>| | |
왜 4개의 메시지가 필요한가?
TCP는 양방향 통신이기 때문이다.
한쪽이 자신의 데이터 전송을 끝냈다고 해서 반대쪽도 반드시 데이터 전송을 끝낸 것은 아니다.
예를 들어 클라이언트는 요청 전송을 마쳤지만 서버는 아직 응답을 보내고 있을 수 있다.
따라서 각 방향의 데이터 전송 종료를 별도로 처리할 수 있다.
5-1. FIN을 보낸 쪽
클라이언트가 더 이상 보낼 데이터가 없으면 FIN을 보낼 수 있다.
Client Server
FIN
------------------------>
서버는 이를 받고 ACK를 전송한다.
이 시점에 클라이언트의 송신 방향은 종료 절차에 들어가지만, 서버는 자신의 방향으로 데이터를 더 보낼 수 있다.
이처럼 TCP는 반쪽 종료(Half-Close)를 지원한다.
5-2. 서버도 종료할 준비가 되면 FIN 전송
서버가 응답 전송을 완료하고 더 이상 보낼 데이터가 없다면 FIN을 보낼 수 있다.
Client Server
FIN
------------------------>
ACK
<------------------------
FIN
<------------------------
ACK
------------------------>
마지막 ACK를 전송한 쪽은 일반적으로 TIME_WAIT 상태로 들어갈 수 있다.
다만 연결 종료 순서와 상태 전이는 어느 쪽이 먼저 종료를 시작하는지, 동시 종료인지 등에 따라 달라질 수 있다.
6. TIME_WAIT란 무엇인가?
Linux 서버에서 자주 보는 TCP 상태 중 하나가 TIME_WAIT다.
확인 명령어:
ss -ant state time-wait
TIME_WAIT는 TCP 연결을 종료한 쪽이 일정 시간 동안 연결 종료 정보를 유지하는 상태다.
TIME_WAIT가 필요한 대표적인 이유는 두 가지다.
- 마지막 ACK가 손실되었을 때 상대방이 FIN을 재전송하면 다시 응답할 수 있도록 하기 위해서
- 이전 연결에서 발생한 지연 패킷이 새로운 연결에 혼동을 일으키지 않도록 하기 위해서
즉, TIME_WAIT는 TCP가 안전하게 연결을 종료하기 위한 정상적인 메커니즘이다.
6-1. TIME_WAIT가 많이 발생하는 이유
예를 들어 API 서버가 짧은 TCP 연결을 매우 많이 처리한다고 하자.
Client | | TCP 연결 v API Server | | 요청 처리 v TCP 연결 종료 | v TIME_WAIT
짧은 연결이 반복되면 TIME_WAIT 상태도 증가할 수 있다.
특히 다음 환경에서 자주 관찰된다.
- HTTP/1.1에서 연결 재사용이 제한적인 환경
- 짧은 연결을 반복하는 API 클라이언트
- 외부 시스템으로 대량의 요청을 보내는 서버
- 프록시 또는 게이트웨이
- 대량의 단기 TCP 세션을 처리하는 서비스
TIME_WAIT가 많다는 사실만으로 장애라고 단정해서는 안 된다.
전체 연결 수, 발생 속도, 로컬 Port 사용량, 실제 연결 실패 여부 등을 함께 확인해야 한다.
6-2. TIME_WAIT 개수 확인하기
전체 TCP 상태를 확인한다.
ss -ant
TIME_WAIT만 확인한다.
ss -ant state time-wait
개수만 확인한다.
ss -ant state time-wait | wc -l
전체 상태를 요약하려면 다음 명령어를 사용한다.
ss -s
여기서 주의할 점은 TIME_WAIT 개수가 많다고 무조건 서버의 Port가 고갈된다는 뜻은 아니라는 것이다.
TCP 연결을 식별하는 주소와 Port 조합, 연결 방향, 커널의 Port 할당 정책 등에 따라 실제 영향이 달라진다.
6-3. TIME_WAIT가 증가할 때 점검할 사항
다음 순서로 확인한다.
ss -s ss -ant state time-wait ss -ant | head -n 30
그리고 애플리케이션에서 연결을 재사용하고 있는지 확인한다.
예를 들어 HTTP 클라이언트가 매 요청마다 새 TCP 연결을 생성하는 구조라면 Connection Pool이나 Keep-Alive 설정을 검토할 수 있다.
단순히 TIME_WAIT를 강제로 줄이기 위해 커널 파라미터를 변경하는 것은 권장하지 않는다. 먼저 연결 생성 패턴과 실제 자원 고갈 여부를 확인해야 한다.
7. CLOSE_WAIT란 무엇인가?
TIME_WAIT와 혼동하기 쉬운 상태가 CLOSE_WAIT다.
CLOSE_WAIT는 상대방이 FIN을 보냈고, 로컬 TCP 스택이 이를 ACK했지만 로컬 애플리케이션이 아직 자신의 송신 방향을 종료하지 않은 상태를 의미한다.
예를 들어 다음과 같다.
Client Server
FIN
------------------------>
ACK
<------------------------
서버는 FIN을 수신하고 ACK를 보냈다.
하지만 서버 애플리케이션은 아직 자신의 연결을 종료하지 않았다.
따라서 서버 측 Socket이 CLOSE_WAIT 상태에 머무를 수 있다.
7-1. CLOSE_WAIT가 증가하는 원인
대표적인 원인은 다음과 같다.
- 애플리케이션이 Socket을 닫지 않음
- 예외 발생 후 연결 정리가 누락됨
- DB 연결 또는 HTTP 연결을 반환하지 않음
- 외부 서비스 연결을 종료하는 코드가 잘못됨
- 연결을 관리하는 라이브러리나 Pool에 문제가 있음
특히 CLOSE_WAIT가 지속적으로 증가한다면 애플리케이션의 연결 종료 처리를 우선적으로 확인해야 한다.
7-2. CLOSE_WAIT 확인하기
ss -ant state close-wait
개수를 확인한다.
ss -ant state close-wait | wc -l
PID와 프로그램 정보를 포함해 확인하려면 다음 명령어를 사용할 수 있다.
ss -antp state close-wait
실행 권한과 시스템 환경에 따라 프로세스 정보가 표시되지 않을 수 있다.
예를 들어 다음과 같은 결과가 나타난다고 가정하자.
State Recv-Q Send-Q Local Address:Port Peer Address:Port CLOSE-WAIT 0 0 192.168.10.100:8080 192.168.10.50:53124 CLOSE-WAIT 0 0 192.168.10.100:8080 192.168.10.51:53125 CLOSE-WAIT 0 0 192.168.10.100:8080 192.168.10.52:53126
이 상태가 계속 증가한다면 해당 애플리케이션이 연결을 적절히 종료하고 있는지 확인해야 한다.
다만 CLOSE_WAIT가 일시적으로 나타나는 것 자체는 정상일 수 있다. 중요한 것은 개수가 지속적으로 증가하는지, 오래된 연결이 남아 있는지, 서비스 장애와 연관되는지다.
8. TIME_WAIT와 CLOSE_WAIT의 차이
두 상태는 의미가 다르다.
항목TIME_WAITCLOSE_WAIT의미종료 절차의 안전성을 위해 연결 정보를 유지상대방의 FIN을 받았지만 로컬 종료가 완료되지 않음주로 확인할 사항연결 생성·종료 빈도, Port 사용량애플리케이션의 Socket 종료 처리많이 발생하는 상황짧은 TCP 연결이 반복됨애플리케이션이 연결을 제때 닫지 못함그 자체가 장애인가?아니오아니오지속 증가 시연결 패턴과 자원 사용량 점검애플리케이션 및 연결 관리 점검
핵심은 다음과 같다.
TIME_WAIT → TCP 종료 절차의 일부 CLOSE_WAIT → 상대방의 종료 요청을 받았지만 로컬 애플리케이션의 종료가 완료되지 않은 상태
따라서 TIME_WAIT와 CLOSE_WAIT를 동일한 방식으로 처리해서는 안 된다.
9. 실제 장애 사례 1 — CLOSE_WAIT가 계속 증가하는 경우
상황:
서비스는 실행 중이다. CPU와 메모리도 정상이다. 하지만 CLOSE_WAIT가 계속 증가한다.
먼저 상태를 확인한다.
ss -s
다음으로:
ss -antp state close-wait
특정 애플리케이션이 다수의 CLOSE_WAIT 연결을 보유하고 있는지 확인한다.
예를 들어 Python API 서버가 외부 API에 요청을 보내고 연결을 정리하지 않는 상황을 가정할 수 있다.
API Server
|
| HTTP Request
v
External API
|
| FIN
v
API Server
|
| ACK
v
CLOSE_WAIT
상대방은 연결을 종료했지만 로컬 프로그램이 Socket을 닫지 않는다면 연결이 남아 있을 수 있다.
이때는 다음을 확인한다.
- 어떤 PID가 해당 연결을 보유하고 있는가?
- 어떤 원격 IP와 Port에 연결되어 있는가?
- 애플리케이션의 연결 종료 코드가 정상적으로 실행되는가?
- 예외 상황에서도 Socket과 응답 객체를 정리하는가?
- HTTP Client나 DB Pool을 올바르게 사용하고 있는가?
애플리케이션 코드에서는 연결 정리 로직을 명확히 관리해야 한다.
Python에서는 예를 들어 컨텍스트 매니저를 활용할 수 있다.
import requests
with requests.Session() as session:
response = session.get(
"https://example.com",
timeout=5
)
response.raise_for_status()
이 예제는 Session 자원을 명시적으로 관리하는 기본 형태다. 실제 운영 환경에서는 응답 객체의 소비·종료, Session 재사용 정책, 예외 처리 등을 함께 설계해야 한다.
중요한 것은 CLOSE_WAIT 상태를 단순히 커널 설정으로 해결하려고 하지 않는 것이다. 근본 원인은 애플리케이션의 연결 관리에 있을 수 있다.
10. 실제 장애 사례 2 — TIME_WAIT가 매우 많은 경우
상황:
API 서버에서 TIME_WAIT가 빠르게 증가한다.
먼저 상태를 확인한다.
ss -s
다음으로:
ss -ant state time-wait
어떤 주소와 Port에서 연결이 집중적으로 발생하는지 확인한다.
ss -ant state time-wait | head -n 30
여기서 특정 서비스가 외부로 짧은 연결을 반복하고 있다면 다음 사항을 검토한다.
- HTTP Keep-Alive 사용 여부
- HTTP Connection Pool 설정
- 요청마다 새 Client 객체를 생성하는지
- 외부 서비스 연결을 불필요하게 반복하는지
- 실제로 로컬 Port 고갈이 발생하고 있는지
예를 들어 다음과 같은 구조라면 연결 생성·종료가 반복된다.
Request 1 → TCP 연결 생성 → 요청 → 종료 Request 2 → TCP 연결 생성 → 요청 → 종료 Request 3 → TCP 연결 생성 → 요청 → 종료
반대로 연결을 재사용할 수 있다면:
TCP 연결 생성
|
+── Request 1
|
+── Request 2
|
+── Request 3
|
TCP 연결 종료
와 같은 구조를 사용할 수 있다.
단, 연결 재사용은 서버와 클라이언트의 동작 및 애플리케이션 프로토콜에 맞게 설정해야 한다.
11. 실제 장애 사례 3 — TCP Retransmission이 증가하는 경우
상황:
애플리케이션 응답이 느리다. 일부 요청은 정상이고 일부 요청은 지연된다.
서버에서 패킷을 캡처한다.
tcpdump -nn -i ens160 'tcp port 443'
동일한 Sequence 범위가 반복해서 나타나는지 확인한다.
또한 다음 정보를 확인한다.
ss -tin
주요 점검 항목은 다음과 같다.
- RTT가 평소보다 증가했는가?
- RTO가 증가했는가?
- 재전송이 실제로 반복되고 있는가?
- 수신 측의 ACK가 돌아오지 않는가?
- 특정 Client 또는 특정 경로에서만 발생하는가?
가능하다면 클라이언트와 서버 양쪽에서 동시에 패킷을 캡처한다.
Client Capture
|
| Packet 전송
v
Network
|
v
Server Capture
예를 들어 클라이언트 캡처에는 패킷이 보이지만 서버 캡처에는 없다면, 두 캡처 지점 사이의 네트워크 구간을 조사해야 한다.
반대로 서버 캡처에서 요청을 확인했는데 서버 응답이 나오지 않는다면 서버의 TCP 처리, 애플리케이션, 방화벽 등의 상태를 점검한다.
패킷 캡처만으로 원인이 즉시 확정되지 않을 수 있으므로 양방향 흐름과 시스템 지표를 함께 분석하는 것이 중요하다.
12. tcpdump에서 TCP 상태를 분석하는 방법
실무에서는 다음 명령어를 자주 사용한다.
12-1. 특정 Port 패킷 확인
tcpdump -nn -i ens160 'tcp port 443'
12-2. SYN 패킷 확인
tcpdump -nn -i ens160 'tcp[tcpflags] & tcp-syn != 0'
SYN 플래그가 설정된 패킷을 확인할 수 있다. SYN과 ACK가 함께 설정된 패킷도 포함될 수 있다.
12-3. FIN 패킷 확인
tcpdump -nn -i ens160 'tcp[tcpflags] & tcp-fin != 0'
연결 종료 과정에서 FIN이 전송되는지 확인한다.
12-4. RST 패킷 확인
tcpdump -nn -i ens160 'tcp[tcpflags] & tcp-rst != 0'
연결이 Reset되는 상황을 분석할 때 사용한다.
12-5. 패킷을 파일로 저장
tcpdump -nn -i ens160 -s 0 -w /tmp/tcp-capture.pcap 'tcp port 443'
캡처를 종료한 후 파일을 분석한다.
tcpdump -nn -r /tmp/tcp-capture.pcap
패킷 파일에는 통신 메타데이터와 경우에 따라 애플리케이션 데이터가 포함될 수 있다. 민감 정보가 캡처되지 않도록 주의하고, 운영 환경에서는 승인된 범위에서 필요한 시간과 필터만 사용한다.
13. TCP 장애 분석 실전 체크리스트
TCP 연결이 느리거나 끊긴다면 다음 순서로 점검한다.
1단계: TCP 상태 확인
ss -s
전체 연결 상태를 확인한다.
2단계: 특정 상태 확인
ss -ant state established ss -ant state time-wait ss -ant state close-wait
3단계: 프로세스 확인
ss -antp
어떤 프로세스가 연결을 보유하는지 확인한다.
4단계: TCP 세부 정보 확인
ss -tin
RTT, 재전송 관련 정보, 혼잡 제어 정보 등을 확인한다.
5단계: 패킷 확인
tcpdump -nn -i ens160 'tcp port 443'
SYN, ACK, FIN, RST와 재전송 흐름을 확인한다.
6단계: 애플리케이션 로그 확인
TCP 연결이 정상적으로 성립했다면 애플리케이션 로그와 요청 처리 시간을 확인한다.
14. 핵심 개념 최종 정리
개념핵심 역할장애 분석 관점Sequence NumberTCP 데이터의 바이트 위치 추적데이터 순서와 재전송 분석ACK Number다음에 받을 바이트 위치 확인데이터 수신 여부 분석Receive Window수신 가능한 데이터 양 광고수신 버퍼와 흐름 제어 분석Congestion Window네트워크 혼잡을 고려한 송신 제한처리량과 혼잡 분석Retransmission손실된 것으로 판단한 데이터 재전송패킷 손실과 ACK 흐름 분석TIME_WAIT종료 과정의 안전성 확보연결 생성·종료 패턴 분석CLOSE_WAIT상대방 FIN 이후 로컬 종료 대기애플리케이션의 Socket 종료 확인FIN정상적인 연결 종료 절차종료 흐름 확인RST연결 초기화연결 거부·강제 종료 분석
마무리
TCP를 깊게 이해한다는 것은 단순히 SYN, ACK, FIN이라는 플래그를 외우는 것이 아니다.
실제 장애에서는 패킷이 어떤 순서로 전달되고, 어느 지점에서 ACK가 멈추며, 재전송이 발생하는 이유가 무엇인지 파악해야 한다.
특히 다음 세 가지는 반드시 기억하자.
첫째, TIME_WAIT가 많다는 이유만으로 장애라고 판단하지 않는다. 정상적인 연결 종료 과정에서 발생할 수 있으므로 실제 자원 고갈이나 서비스 영향이 있는지 확인해야 한다.
둘째, CLOSE_WAIT가 지속적으로 증가한다면 애플리케이션의 연결 종료 처리를 확인한다. 상대방의 FIN을 받은 후에도 로컬 애플리케이션이 연결을 닫지 않으면 상태가 유지될 수 있다.
셋째, TCP Retransmission은 패킷 손실이나 ACK 지연 등을 조사하기 위한 중요한 단서다. 클라이언트와 서버의 패킷을 비교하고 RTT, 라우팅, 방화벽, 서버 처리 상태를 함께 확인해야 한다.
다음 편에서는 TCP와 UDP의 기본 개념을 넘어 DNS의 동작 원리와 실제 DNS 장애 분석으로 넘어간다.
DNS 조회 과정, 재귀 질의와 반복 질의, DNS 캐시, TTL, UDP와 TCP 53번 Port의 차이, dig와 tcpdump를 이용한 DNS 장애 분석까지 살펴보겠다.
댓글
아직 댓글이 없습니다.
로그인 후 댓글을 남길 수 있습니다.