- Authors
- Name
- 개요
- 1. TCP 3-Way Handshake 이해하기
- 2. 흔한 TCP 연결 문제들
- 3. 디버깅 도구 활용
- 4. TCP 튜닝 파라미터
- 5. Connection Tracking (conntrack)
- 6. 실전 디버깅 시나리오
- 7. 모니터링 자동화 스크립트
- 8. 정리: TCP 디버깅 체크리스트
개요
서버 운영이나 백엔드 개발을 하다 보면 "연결이 안 돼요", "타임아웃이 나요", "간헐적으로 끊겨요"라는 문제를 자주 접하게 됩니다. 이런 문제의 대부분은 TCP/IP 레벨에서 발생하며, 정확한 원인을 파악하려면 TCP의 동작 원리와 디버깅 도구를 제대로 이해해야 합니다.
이 글에서는 TCP 연결의 기본 원리부터 실무에서 바로 활용할 수 있는 디버깅 기법까지 단계적으로 정리합니다.
1. TCP 3-Way Handshake 이해하기
1.1 연결 수립 과정
TCP 연결은 3-way handshake를 통해 수립됩니다.
Client Server
| |
|--- SYN (seq=x) ------->| (1) 클라이언트가 SYN 전송
| |
|<-- SYN-ACK (seq=y, | (2) 서버가 SYN-ACK 응답
| ack=x+1) ----------|
| |
|--- ACK (ack=y+1) ----->| (3) 클라이언트가 ACK 전송
| |
|== 연결 수립 완료 ========|
각 단계에서 문제가 발생할 수 있으며, 어느 단계에서 실패하느냐에 따라 원인이 달라집니다.
1.2 TCP 연결 상태 전이
TCP 소켓은 다양한 상태를 가집니다. 디버깅 시 이 상태를 이해하는 것이 핵심입니다.
LISTEN → 서버가 연결 대기 중
SYN_SENT → 클라이언트가 SYN 전송 후 대기 중
SYN_RECV → 서버가 SYN 수신 후 SYN-ACK 전송, ACK 대기 중
ESTABLISHED → 연결 수립 완료
FIN_WAIT_1 → 능동적 종료 시작 (FIN 전송)
FIN_WAIT_2 → FIN에 대한 ACK 수신, 상대방 FIN 대기
CLOSE_WAIT → 수동적 종료 (상대방 FIN 수신)
TIME_WAIT → 연결 종료 후 대기 (2MSL)
LAST_ACK → 마지막 ACK 대기
CLOSING → 양쪽 동시 종료
CLOSED → 연결 종료 완료
1.3 연결 종료 (4-Way Handshake)
Client Server
| |
|--- FIN --------------->| (1) 클라이언트 종료 요청
|<-- ACK ----------------| (2) 서버 ACK
| |
|<-- FIN ----------------| (3) 서버 종료 요청
|--- ACK --------------->| (4) 클라이언트 ACK
| |
|-- TIME_WAIT (2MSL) ----|
2. 흔한 TCP 연결 문제들
2.1 Connection Refused (연결 거부)
서버 측에서 해당 포트를 리슨하고 있지 않을 때 RST 패킷으로 응답합니다.
# 증상 확인
$ curl -v http://192.168.1.100:8080
* Trying 192.168.1.100:8080...
* connect to 192.168.1.100 port 8080 failed: Connection refused
# 서버에서 포트 확인
$ ss -tlnp | grep 8080
# (출력 없음 = 리슨하는 프로세스가 없음)
# 방화벽 확인
$ iptables -L -n | grep 8080
$ firewall-cmd --list-ports
주요 원인:
- 서비스가 시작되지 않음
- 서비스가 다른 포트에 바인딩됨
- 서비스가 localhost(127.0.0.1)에만 바인딩됨
- 방화벽에서 차단
2.2 Connection Timeout (연결 시간 초과)
SYN 패킷을 보냈으나 응답이 없을 때 발생합니다.
# 증상
$ curl --connect-timeout 5 http://10.0.0.50:3306
curl: (28) Connection timed out after 5001 milliseconds
# SYN 재전송 확인
$ netstat -s | grep -i retrans
12345 segments retransmitted
678 SYNs to LISTEN sockets dropped
# 커널의 SYN 재전송 횟수 확인
$ cat /proc/sys/net/ipv4/tcp_syn_retries
6
# 재전송 간격: 1초 → 2초 → 4초 → 8초 → 16초 → 32초 (총 약 63초)
주요 원인:
- 네트워크 경로 문제 (라우팅 오류)
- 방화벽이 SYN 패킷을 DROP (REJECT가 아닌)
- 서버가 과부하로 응답 불가
- 중간 네트워크 장비 문제
2.3 SYN Flood 공격
# SYN_RECV 상태가 비정상적으로 많은 경우
$ ss -s
Total: 15234
TCP: 12890 (estab 234, closed 45, orphaned 12, timewait 567)
$ ss -tn state syn-recv | wc -l
8923 # 비정상적으로 높은 수치
# SYN 쿠키 활성화 확인
$ cat /proc/sys/net/ipv4/tcp_syncookies
1
# SYN backlog 확인
$ cat /proc/sys/net/ipv4/tcp_max_syn_backlog
1024
# SYN flood 방어 설정
$ sysctl -w net.ipv4.tcp_syncookies=1
$ sysctl -w net.ipv4.tcp_max_syn_backlog=4096
$ sysctl -w net.ipv4.tcp_synack_retries=2
2.4 RST (Reset) 패킷 분석
RST 패킷은 여러 상황에서 전송됩니다.
# RST 원인 파악을 위한 tcpdump
$ tcpdump -i eth0 'tcp[tcpflags] & (tcp-rst) != 0' -nn
# 출력 예시
14:23:01.123456 IP 192.168.1.10.45678 > 10.0.0.5.80: Flags [R], seq 0, ack 1234567, win 0, length 0
14:23:01.234567 IP 10.0.0.5.80 > 192.168.1.10.45678: Flags [R.], seq 0, ack 7654321, win 0, length 0
RST 발생 원인:
- 닫힌 포트로의 연결 시도
- 애플리케이션의 강제 종료 (SO_LINGER 설정)
- TCP keepalive 실패
- 방화벽의 연결 추적 테이블 오버플로
2.5 TIME_WAIT 과다
# TIME_WAIT 상태 카운트
$ ss -s
TCP: 8934 (estab 234, closed 45, orphaned 12, timewait 8123)
# TIME_WAIT 상태의 소켓 상세 확인
$ ss -tn state time-wait | head -20
Recv-Q Send-Q Local Address:Port Peer Address:Port
0 0 192.168.1.10:45678 10.0.0.5:80
0 0 192.168.1.10:45679 10.0.0.5:80
...
# TIME_WAIT 소켓 재사용 설정
$ sysctl -w net.ipv4.tcp_tw_reuse=1
# TIME_WAIT 타임아웃 확인 (수정 불가, 기본 60초)
$ cat /proc/sys/net/ipv4/tcp_fin_timeout
60
3. 디버깅 도구 활용
3.1 ss (Socket Statistics)
ss는 netstat의 현대적 대안으로 더 빠르고 상세한 정보를 제공합니다.
# 모든 TCP 리스닝 소켓 + 프로세스 정보
$ ss -tlnp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1234,fd=3))
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=5678,fd=6))
LISTEN 0 128 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=5678,fd=7))
# 특정 상태의 소켓만 필터링
$ ss -tn state established '( dport = :443 )'
Recv-Q Send-Q Local Address:Port Peer Address:Port
0 0 192.168.1.10:45678 10.0.0.5:443
0 0 192.168.1.10:45679 10.0.0.5:443
# 타이머 정보 포함 (재전송, keepalive 등)
$ ss -tnio
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 0 192.168.1.10:22 10.0.0.1:54321
cubic wscale:7,7 rto:204 rtt:1.5/0.75 ato:40 mss:1448 pmtu:1500
rcvmss:1448 advmss:1448 cwnd:10 ssthresh:20 bytes_sent:12345
bytes_acked:12345 bytes_received:6789 segs_out:100 segs_in:80
# Recv-Q/Send-Q 의미 (LISTEN 상태)
# Recv-Q: 현재 SYN backlog 큐에 있는 연결 수
# Send-Q: SYN backlog 큐의 최대 크기
3.2 netstat (레거시이지만 여전히 유용)
# TCP 연결 상태별 카운트
$ netstat -ant | awk '{print $6}' | sort | uniq -c | sort -rn
234 ESTABLISHED
123 TIME_WAIT
45 CLOSE_WAIT
12 LISTEN
5 SYN_SENT
3 FIN_WAIT2
1 SYN_RECV
# 특정 포트의 연결 확인
$ netstat -antp | grep :3306
tcp 0 0 192.168.1.10:3306 192.168.1.20:45678 ESTABLISHED 1234/mysqld
tcp 0 0 192.168.1.10:3306 192.168.1.21:34567 ESTABLISHED 1234/mysqld
# 네트워크 통계 요약
$ netstat -s | head -40
Ip:
123456 total packets received
0 forwarded
0 incoming packets discarded
123456 incoming packets delivered
654321 requests sent out
Tcp:
12345 active connection openings
6789 passive connection openings
123 failed connection attempts
45 connection resets received
234 connections established
567890 segments received
678901 segments sent out
1234 segments retransmitted
3.3 tcpdump 패킷 캡처
# 기본 패킷 캡처 (특정 호스트, 포트)
$ tcpdump -i eth0 host 10.0.0.5 and port 80 -nn
# 3-way handshake만 캡처
$ tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0' -nn
# SYN 패킷만 캡처 (ACK 없이 SYN만)
$ tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn) != 0 and tcp[tcpflags] & (tcp-ack) == 0' -nn
# 파일로 저장 (Wireshark에서 분석용)
$ tcpdump -i eth0 -w /tmp/capture.pcap -c 10000 host 10.0.0.5
# 저장된 파일 읽기
$ tcpdump -r /tmp/capture.pcap -nn
# 패킷 내용 포함 (hex + ASCII)
$ tcpdump -i eth0 -X port 80 -c 5
# 출력 예시 (3-way handshake)
14:30:01.001 IP 192.168.1.10.45678 > 10.0.0.5.80: Flags [S], seq 1234567, win 64240, options [mss 1460,sackOK,TS val 123 ecr 0,nop,wscale 7], length 0
14:30:01.002 IP 10.0.0.5.80 > 192.168.1.10.45678: Flags [S.], seq 7654321, ack 1234568, win 65160, options [mss 1460,sackOK,TS val 456 ecr 123,nop,wscale 7], length 0
14:30:01.002 IP 192.168.1.10.45678 > 10.0.0.5.80: Flags [.], ack 7654322, win 502, options [nop,nop,TS val 123 ecr 456], length 0
# HTTP 요청/응답 내용까지 캡처
$ tcpdump -i eth0 -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' -c 20
3.4 Wireshark 기본 필터
tcpdump로 캡처한 pcap 파일을 Wireshark에서 분석할 때 유용한 필터입니다.
# 기본 디스플레이 필터
tcp.port == 80 # 특정 포트
ip.addr == 192.168.1.10 # 특정 IP
tcp.flags.syn == 1 && tcp.flags.ack == 0 # SYN만
tcp.flags.reset == 1 # RST 패킷
tcp.analysis.retransmission # 재전송 패킷
tcp.analysis.duplicate_ack # 중복 ACK
tcp.analysis.zero_window # 제로 윈도우
tcp.analysis.window_full # 윈도우 풀
# 스트림 추적
tcp.stream eq 5 # 특정 TCP 스트림
# 시간 기반 필터
frame.time >= "2026-03-08 14:00:00" && frame.time <= "2026-03-08 14:30:00"
# 느린 응답 찾기
tcp.time_delta > 1 # 1초 이상 지연된 패킷
4. TCP 튜닝 파라미터
4.1 Backlog 설정
# listen backlog (SYN 큐 + accept 큐)
$ cat /proc/sys/net/core/somaxconn
4096
# SYN backlog (반-열림 연결 큐)
$ cat /proc/sys/net/ipv4/tcp_max_syn_backlog
1024
# 권장 설정 (고트래픽 서버)
$ sysctl -w net.core.somaxconn=65535
$ sysctl -w net.ipv4.tcp_max_syn_backlog=65535
# 애플리케이션에서도 backlog 설정 필요
# Nginx 예시
# listen 80 backlog=65535;
4.2 Keepalive 설정
# 현재 설정 확인
$ cat /proc/sys/net/ipv4/tcp_keepalive_time
7200 # 기본값: 2시간 (idle 후 첫 probe까지)
$ cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75 # probe 간격 (초)
$ cat /proc/sys/net/ipv4/tcp_keepalive_probes
9 # 최대 probe 횟수
# 빠른 죽은 연결 감지를 위한 설정
$ sysctl -w net.ipv4.tcp_keepalive_time=600 # 10분
$ sysctl -w net.ipv4.tcp_keepalive_intvl=30 # 30초
$ sysctl -w net.ipv4.tcp_keepalive_probes=5 # 5회
# 총 감지 시간: 600 + (30 * 5) = 750초 (12.5분)
4.3 Window Scaling
# 윈도우 스케일링 활성화 (기본값: 1)
$ cat /proc/sys/net/ipv4/tcp_window_scaling
1
# TCP 버퍼 크기 설정 (min, default, max)
$ cat /proc/sys/net/ipv4/tcp_rmem
4096 131072 6291456
$ cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4194304
# 고대역폭 환경 최적화
$ sysctl -w net.ipv4.tcp_rmem="4096 262144 16777216"
$ sysctl -w net.ipv4.tcp_wmem="4096 262144 16777216"
$ sysctl -w net.core.rmem_max=16777216
$ sysctl -w net.core.wmem_max=16777216
# BDP (Bandwidth-Delay Product) 계산
# 대역폭 1Gbps, RTT 10ms의 경우:
# BDP = 1,000,000,000 * 0.01 / 8 = 1,250,000 bytes (약 1.2MB)
# → tcp_rmem/tcp_wmem의 max 값을 BDP 이상으로 설정
4.4 기타 중요한 파라미터
# 포트 범위 (로컬 임시 포트)
$ cat /proc/sys/net/ipv4/ip_local_port_range
32768 60999
# 더 넓은 포트 범위 설정
$ sysctl -w net.ipv4.ip_local_port_range="1024 65535"
# FIN_TIMEOUT (TIME_WAIT → CLOSED 전환 시간)
$ sysctl -w net.ipv4.tcp_fin_timeout=30
# TCP Fast Open 활성화
$ sysctl -w net.ipv4.tcp_fastopen=3
# 최대 파일 디스크립터 수 (소켓도 fd)
$ cat /proc/sys/fs/file-max
1048576
$ ulimit -n
65535
5. Connection Tracking (conntrack)
5.1 conntrack 기본
Linux의 netfilter는 모든 연결을 추적합니다. iptables/nftables 규칙에서 상태 기반 필터링에 사용됩니다.
# conntrack 테이블 확인
$ conntrack -L | head -10
tcp 6 431999 ESTABLISHED src=192.168.1.10 dst=10.0.0.5 sport=45678 dport=80 src=10.0.0.5 dst=192.168.1.10 sport=80 dport=45678 [ASSURED] mark=0 use=1
tcp 6 116 SYN_SENT src=192.168.1.10 dst=10.0.0.50 sport=34567 dport=3306 [UNREPLIED] src=10.0.0.50 dst=192.168.1.10 sport=3306 dport=34567 mark=0 use=1
# conntrack 테이블 카운트
$ conntrack -C
45678
# conntrack 최대값 확인
$ cat /proc/sys/net/nf_conntrack_max
262144
# conntrack 테이블이 가득 차면 새 연결이 DROP됨
# dmesg에서 확인
$ dmesg | grep conntrack
[12345.678] nf_conntrack: table full, dropping packet
5.2 conntrack 최적화
# conntrack 최대값 증가
$ sysctl -w net.nf_conntrack_max=1048576
# conntrack 해시 테이블 크기
$ cat /proc/sys/net/netfilter/nf_conntrack_buckets
65536
# 타임아웃 설정
$ cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
432000 # 5일 (기본값)
# 더 짧은 타임아웃으로 변경
$ sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=86400 # 1일
$ sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
$ sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=60
# 특정 연결 삭제
$ conntrack -D -s 192.168.1.100
$ conntrack -D -p tcp --dport 80
6. 실전 디버깅 시나리오
6.1 시나리오: 웹 서버 간헐적 타임아웃
# 1단계: 현재 연결 상태 확인
$ ss -s
Total: 15234
TCP: 12890 (estab 8234, closed 45, orphaned 12, timewait 4567)
# 2단계: CLOSE_WAIT 확인 (서버 쪽 소켓 누수 의심)
$ ss -tn state close-wait | wc -l
2345 # 너무 많음! 애플리케이션에서 소켓을 닫지 않는 것
# 3단계: 어떤 프로세스가 CLOSE_WAIT 소켓을 가지고 있는지
$ ss -tnp state close-wait | awk '{print $NF}' | sort | uniq -c | sort -rn
2100 users:(("java",pid=5678,fd=...))
200 users:(("python",pid=1234,fd=...))
# 4단계: 해당 프로세스의 fd 수 확인
$ ls -la /proc/5678/fd | wc -l
4567 # 파일 디스크립터 누수 확인
# 5단계: lsof로 상세 확인
$ lsof -p 5678 | grep TCP | grep CLOSE_WAIT | wc -l
2100
6.2 시나리오: 마이크로서비스 간 연결 실패
# 1단계: DNS 확인
$ dig +short service-b.internal
10.0.0.50
# 2단계: 포트 연결 테스트
$ nc -zv -w 3 10.0.0.50 8080
Connection to 10.0.0.50 8080 port [tcp/*] succeeded!
# 또는 실패 시
$ nc -zv -w 3 10.0.0.50 8080
nc: connect to 10.0.0.50 port 8080 (tcp) failed: Connection timed out
# 3단계: traceroute로 네트워크 경로 확인
$ traceroute -T -p 8080 10.0.0.50
traceroute to 10.0.0.50, 30 hops max
1 gateway (10.0.0.1) 0.5 ms 0.4 ms 0.3 ms
2 * * *
3 10.0.0.50 1.2 ms 1.1 ms 1.0 ms
# 4단계: MTU 문제 확인
$ ping -M do -s 1472 10.0.0.50
PING 10.0.0.50 (10.0.0.50) 1472(1500) bytes of data.
ping: local error: message too long, mtu=1400
# MTU 조정
$ ip link set dev eth0 mtu 1400
6.3 시나리오: 대량 트래픽 서버 최적화
# 전체 튜닝 스크립트
cat << 'EOF' > /etc/sysctl.d/99-tcp-tuning.conf
# Backlog 설정
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 65535
# TIME_WAIT 최적화
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
# Keepalive
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
# 버퍼 크기
net.ipv4.tcp_rmem = 4096 262144 16777216
net.ipv4.tcp_wmem = 4096 262144 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
# 포트 범위
net.ipv4.ip_local_port_range = 1024 65535
# SYN flood 방어
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 2
# conntrack
net.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 86400
# TCP Fast Open
net.ipv4.tcp_fastopen = 3
# Window Scaling
net.ipv4.tcp_window_scaling = 1
EOF
# 적용
$ sysctl -p /etc/sysctl.d/99-tcp-tuning.conf
6.4 시나리오: tcpdump로 느린 응답 분석
# 특정 서비스와의 통신 캡처 (30초간)
$ timeout 30 tcpdump -i eth0 -w /tmp/slow.pcap host 10.0.0.5 and port 443
# 캡처 파일 분석 - 재전송 확인
$ tcpdump -r /tmp/slow.pcap 'tcp[tcpflags] & (tcp-syn) != 0' -nn
# SYN 재전송이 보이면 초기 연결 문제
# 캡처 파일 분석 - 데이터 흐름 확인
$ tcpdump -r /tmp/slow.pcap -ttt -nn | head -30
# -ttt: 패킷 간 시간 간격 표시
00:00:00.000000 IP 192.168.1.10.45678 > 10.0.0.5.443: Flags [S], seq 123
00:00:00.001234 IP 10.0.0.5.443 > 192.168.1.10.45678: Flags [S.], seq 456, ack 124
00:00:00.000100 IP 192.168.1.10.45678 > 10.0.0.5.443: Flags [.], ack 457
00:00:00.000500 IP 192.168.1.10.45678 > 10.0.0.5.443: Flags [P.], seq 124:500
00:00:02.345678 IP 10.0.0.5.443 > 192.168.1.10.45678: Flags [P.], seq 457:1200
# ↑ 2초 이상의 간격 = 서버 측 처리 지연
# tshark (CLI Wireshark)로 상세 분석
$ tshark -r /tmp/slow.pcap -q -z io,stat,1
# 1초 간격 통계
$ tshark -r /tmp/slow.pcap -q -z conv,tcp
# TCP 대화별 통계
7. 모니터링 자동화 스크립트
7.1 TCP 상태 모니터링
#!/bin/bash
# tcp_monitor.sh - TCP 연결 상태 모니터링
LOG_FILE="/var/log/tcp_monitor.log"
ALERT_THRESHOLD_TW=5000 # TIME_WAIT 경고 임계치
ALERT_THRESHOLD_CW=100 # CLOSE_WAIT 경고 임계치
ALERT_THRESHOLD_SYNR=500 # SYN_RECV 경고 임계치
while true; do
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# 상태별 카운트
ESTABLISHED=$(ss -tn state established | wc -l)
TIME_WAIT=$(ss -tn state time-wait | wc -l)
CLOSE_WAIT=$(ss -tn state close-wait | wc -l)
SYN_RECV=$(ss -tn state syn-recv | wc -l)
LISTEN=$(ss -tn state listening | wc -l)
echo "$TIMESTAMP ESTAB=$ESTABLISHED TW=$TIME_WAIT CW=$CLOSE_WAIT SYNR=$SYN_RECV LISTEN=$LISTEN" >> "$LOG_FILE"
# 경고 체크
if [ "$TIME_WAIT" -gt "$ALERT_THRESHOLD_TW" ]; then
echo "$TIMESTAMP [WARN] TIME_WAIT=$TIME_WAIT exceeds threshold" >> "$LOG_FILE"
fi
if [ "$CLOSE_WAIT" -gt "$ALERT_THRESHOLD_CW" ]; then
echo "$TIMESTAMP [ALERT] CLOSE_WAIT=$CLOSE_WAIT - possible socket leak!" >> "$LOG_FILE"
fi
if [ "$SYN_RECV" -gt "$ALERT_THRESHOLD_SYNR" ]; then
echo "$TIMESTAMP [ALERT] SYN_RECV=$SYN_RECV - possible SYN flood!" >> "$LOG_FILE"
fi
sleep 10
done
7.2 conntrack 모니터링
#!/bin/bash
# conntrack_monitor.sh
MAX=$(cat /proc/sys/net/nf_conntrack_max)
CURRENT=$(conntrack -C 2>/dev/null || cat /proc/sys/net/netfilter/nf_conntrack_count)
USAGE=$((CURRENT * 100 / MAX))
echo "Conntrack: $CURRENT / $MAX ($USAGE%)"
if [ "$USAGE" -gt 80 ]; then
echo "[WARN] Conntrack table usage above 80%!"
echo "Top source IPs:"
conntrack -L 2>/dev/null | awk '{print $5}' | cut -d= -f2 | sort | uniq -c | sort -rn | head -10
fi
8. 정리: TCP 디버깅 체크리스트
문제 발생 시 다음 순서로 확인합니다.
1. 기본 연결 확인
□ ping / traceroute로 네트워크 경로 확인
□ nc -zv 또는 telnet으로 포트 연결 테스트
□ DNS 해석 확인 (dig, nslookup)
2. 소켓 상태 확인
□ ss -tlnp로 리스닝 포트 확인
□ ss -s로 전체 소켓 통계 확인
□ 비정상 상태 (CLOSE_WAIT, SYN_RECV 과다) 체크
3. 패킷 레벨 분석
□ tcpdump로 패킷 캡처
□ RST, 재전송, 지연 분석
□ Wireshark로 상세 분석
4. 커널 파라미터 확인
□ backlog 크기
□ conntrack 테이블 사용률
□ 파일 디스크립터 제한
5. 애플리케이션 레벨
□ 연결 풀 설정
□ 타임아웃 설정
□ 에러 로그 확인
TCP/IP 문제는 계층적으로 접근하는 것이 핵심입니다. 물리적/네트워크 레벨부터 시작하여 애플리케이션 레벨로 올라가면서 원인을 좁혀 나가는 것이 효율적입니다.