网络排错全景
网络排错全景
[!abstract] 定位 网络是最容易「谁都觉得自己没问题」的盲区。本手册覆盖 TCP 状态机排查、DNS 排查、抓包分析、以及从用户到服务的全链路排查方法论。
一、TCP 状态机 —— 面试最常考
stateDiagram-v2
[*] --> CLOSED
CLOSED --> SYN_SENT: 主动连接
SYN_SENT --> ESTABLISHED: 收到 SYN+ACK
CLOSED --> SYN_RECV: 被动连接
SYN_RECV --> ESTABLISHED: 收到 ACK
ESTABLISHED --> FIN_WAIT1: 主动关闭
FIN_WAIT1 --> FIN_WAIT2: 收到 ACK
FIN_WAIT2 --> TIME_WAIT: 收到 FIN
TIME_WAIT --> CLOSED: 等待 2MSL
ESTABLISHED --> CLOSE_WAIT: 收到 FIN(被动方)
CLOSE_WAIT --> LAST_ACK: 应用调用 close()
LAST_ACK --> CLOSED: 收到 ACK
各状态的面试考点
| 状态 | 大量堆积说明什么 | 排查命令 |
|---|---|---|
SYN_SENT | 连接发不出去 → 目标不可达/防火墙阻断 | telnet IP PORT 测试 |
SYN_RECV | SYN Flood 攻击,或半连接队列满 | ss -s 看 synrecv,sysctl net.ipv4.tcp_max_syn_backlog |
TIME_WAIT | 大量短连接 → 用长连接 / 调内核参数 | ss -ant state time-wait | wc -l |
CLOSE_WAIT | 应用层 bug! 收到 FIN 但应用没调 close() → 连接泄漏 | lsof -p PID 找泄漏源 |
ESTABLISHED | 正常,但数量超过 ulimit 会无法新建 | ss -s 看 TCP 总数 |
[!warning] CLOSE_WAIT 是应用层问题 面试被问到可以说:「CLOSE_WAIT 堆积一定是应用代码的问题——HTTP Client 或连接池没有正确关闭连接。这跟内核参数无关。」
二、抓包分析 —— tcpdump 速查
常用过滤
# 基础语法:tcpdump -i <网卡> <过滤条件> -w <文件>
# 抓指定端口
tcpdump -i eth0 port 8080
# 抓指定主机
tcpdump -i eth0 host 10.0.0.5
# 抓 HTTP 请求(只看 GET/POST)
tcpdump -i eth0 -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
# 抓 TCP SYN 包
tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0'
# 抓 TCP RST 包
tcpdump -i eth0 'tcp[tcpflags] & tcp-rst != 0'
# 存文件(限制大小,自动轮转)
tcpdump -i eth0 -w /tmp/cap.pcap -C 100 -W 5
# -C 100: 每个文件 100MB,-W 5: 最多 5 个文件,循环覆盖
# 在 Wireshark 中打开 .pcap 分析
面试高频:三次握手在 tcpdump 里长什么样
# 三次握手
→ SYN [S] seq=0
← SYN+ACK [S.] seq=0 ack=1
→ ACK [.] ack=1
# TCP 标志位速记:
# S = SYN, F = FIN, R = RST, P = PSH, . = ACK
三、全链路网络排查
[!tip] 面试金句 「从外往里查,逐层排除:DNS → 网络通不通 → 端口有没有监听 → 防火墙拦没拦 → 应用有没有响应。」
graph LR
A[用户报障] --> B[DNS 解析对吗?]
B -->|dig/nslookup| C[网络通吗?]
C -->|ping/mtr/telnet| D[端口监听吗?]
D -->|ss/netstat| E[防火墙拦了吗?]
E -->|iptables/安全组| F[应用有响应吗?]
F -->|curl| G[SSL 证书正常吗?]
逐层命令
# 1. DNS 解析
dig api.example.com # 查 A 记录
dig api.example.com @8.8.8.8 # 指定 DNS 服务器
nslookup api.example.com # Windows 也可以用
# 注意:CNAME 链、TTL 值、返回了几个 IP
# 2. 网络通不通
ping -c 4 10.0.0.1 # 基础连通性(ICMP,可能被禁)
mtr 10.0.0.1 -r -c 10 # 看哪一跳丢包(mtr 是 ping + traceroute 的合体)
traceroute 10.0.0.1 # 路由追踪
# 3. 端口通不通
telnet 10.0.0.1 8080 # 最原始
nc -zv 10.0.0.1 8080 # 更快,-z 不发送数据
timeout 3 bash -c 'cat < /dev/null > /dev/tcp/10.0.0.1/8080' # 纯 bash 无依赖
# 4. 端口有没有监听
ss -tlnp | grep 8080 # -t tcp, -l listening, -n 不解析, -p 进程名
# 注意:0.0.0.0:8080 监听所有网卡,127.0.0.1:8080 只监听本地
# 5. 防火墙
iptables -L -n -v # 看规则
# 临时关防火墙测试(生产别干)
# iptables -P INPUT ACCEPT
# 6. 应用有没有响应
curl -v http://10.0.0.1:8080/health # -v 看请求详情(DNS 解析、TCP 连接、SSL 握手、HTTP 响应)
curl -w '\n%{time_namelookup}\n%{time_connect}\n%{time_total}\n' -o /dev/null -s http://example.com
# time_namelookup: DNS 耗时
# time_connect: TCP 连接耗时
# time_total: 总耗时
# 7. SSL 证书
openssl s_client -connect example.com:443 -servername example.com | openssl x509 -noout -dates
四、TIME_WAIT 深度解析
[!important] 必考,且必考 NAT 下的陷阱
为什么需要 TIME_WAIT?
两个原因:
- 保证最后一个 ACK 能被对端收到。 如果对端没收到 ACK 会重发 FIN,TIME_WAIT 状态能处理这个重传。
- 防止旧连接的包窜到新连接。 等待 2MSL 确保这个连接的所有包都在网络中消失。
内核参数精讲
# ✅ 可以开的
net.ipv4.tcp_tw_reuse = 1 # 允许 TIME_WAIT socket 被复用(仅客户端)
# ❌ 绝对不能开的(NAT 环境)
net.ipv4.tcp_tw_recycle = 0 # Linux 4.12 已移除!依赖时间戳,NAT 下必丢包
# ✅ 推荐的
net.ipv4.ip_local_port_range = 10240 65535 # 扩大可用端口范围
net.ipv4.tcp_max_tw_buckets = 262144 # 允许的 TIME_WAIT 总数
net.ipv4.tcp_fin_timeout = 15 # FIN_WAIT2 超时(秒)
# 生效
sysctl -p
[!warning]
tcp_tw_recycle的血泪史 这个参数在 2015 年前后被大量博客推荐作为「性能优化」,但实际上:
- 它会检查每个包的时间戳是否递增
- 在 NAT 环境下,不同客户端的时间戳不同步
- 导致正常 SYN 包被当作「旧连接重传」丢弃
- 表现就是:随机用户连不上,查了半天一切正常,最终发现是 NAT + tcp_tw_recycle 的锅
面试提到这个 = 你有实战经验。
根治:用长连接
# Nginx upstream keepalive(见 [[Nginx 排错调优速查]])
upstream backend {
server 10.0.0.1:8080;
keepalive 32;
}
# Python requests 使用 Session(连接复用)
session = requests.Session()
session.get('http://api.example.com/data')
session.get('http://api.example.com/other') # 复用 TCP 连接
五、常见网络故障速查
场景 1:间歇性超时
# 可能原因:DNS 慢、丢包、负载不均
mtr <IP> -r -c 100 # 看丢包率
tcpdump -i eth0 host <IP> -w cap.pcap # 抓包看重传
# 在 Wireshark 中:Statistics → TCP Stream Graphs → Time-Sequence
场景 2:部分用户连不上
# 可能原因:DNS 污染、CDN 节点异常、NAT 下的 tcp_tw_recycle
dig api.example.com @114.114.114.114 # 换 DNS 对比
curl -v --resolve api.example.com:443:<IP> https://api.example.com # 绕过 DNS 直接测
场景 3:连接数打满
ss -s # TCP 总体统计
ss -ant | awk '{print $6}' | sort | uniq -c | sort -rn # 各状态数量
netstat -ant | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head # 哪个 IP 连接最多
六、面试话术模板
[!quote] 被问「网络故障怎么排查」
「我从外往里查,七层逐层排除。」
「第一层 DNS:dig 确认域名解析是否正确,TTL 是否合理,有没有 CNAME 串了好几层。」
「第二层网络连通性:ping 和 mtr 看是否可达,traceroute 看走哪条路由。」
「第三层端口:telnet 或 nc 测端口通不通。如果端口不通,上服务器 ss -tlnp 确认是否在监听,注意 0.0.0.0 和 127.0.0.1 的区别。」
「第四层防火墙:iptables -L -n 和服务器的安全组/云防火墙。经常是安全组改了没通知就出问题。」
「第五层应用:curl -v 发请求看完整的握手和响应过程,包括 SSL 证书有效期。」
「如果有间歇性问题,上 tcpdump 抓包,看 TCP 重传、RST 包、握手失败的具体原因。抓完在 Wireshark 里分析是最快的。」
「TIME_WAIT 堆积的话,优先看能不能改长连接,而不是无脑调内核参数——尤其是 tcp_tw_recycle 在 NAT 环境下会导致丢包,生产绝对不能开。」
#sre #网络 #tcp #面试