TCP 排障入门指南(新人版)
TCP 排障入门指南
本文从团队知识库中提炼而来,面向刚接触网络排障的新同学。不讲大而全的理论,只讲排障时真正用得上的东西。
第一课:排障的核心思维
记住三句话,比记住任何工具都重要:
- 一个错误现象可能对应多个完全不同的根因 —— 不要看到报错就下结论
- 不要相信报错信息的字面意思 —— 比如
net_write_timeout报错不一定是超时 - 拿证据推进问题 —— 每一步推理都要有抓包、日志、堆栈等证据支撑
排障工具的优先级:
1 | 抓包(tcpdump/wireshark) ← 网络层面的终极证据,优先用 |
第二课:你必须知道的 TCP 基础
三次握手
1 | Client Server |
握手失败的常见原因:
| 现象 | 原因 | 怎么查 |
|---|---|---|
| 精确 1s/3s/7s 超时 | SYN 被丢弃后重传 | 全连接队列满?防火墙 DROP? |
| Connection refused | 端口没人监听 | ss -lntp 看端口 |
| 偶发连接超时 | 半连接/全连接队列满 | netstat -s | grep listen |
| NAT 下偶发不通 | tcp_tw_recycle 丢 SYN |
netstat -s | grep "time stamp" |
新人必记:碰到精确的 1s、3s、7s 超时,几乎可以断定是 SYN 丢包重传。SYN 重传间隔是 1s→2s→4s→8s 指数退避。
四次挥手
1 | 主动方 被动方 |
| 状态堆积 | 说明 | 排查 |
|---|---|---|
| 大量 CLOSE_WAIT | 你的应用没调 close() | ss -tp 看是哪个进程 |
| 大量 TIME_WAIT | 短连接太多,通常无害 | 用 tcp_tw_reuse 缓解 |
新人必记:CLOSE_WAIT 是被动关闭方的状态,问题一定在你这边的应用代码。
传输性能公式
1 | 理论最大吞吐 ≈ min(发送窗口, 接收窗口, 拥塞窗口) / RTT |
速度上不去时检查:
- Buffer 太小:
ss -tm看 skmem,检查tcp_rmem/tcp_wmem - RTT 太大:RTT 越大,慢启动越久,丢包恢复越慢
- 丢包:一旦丢包 RTO 指数退避(最大 120 秒),速度断崖式下降
第三课:五个必会的排障命令
1. ss —— 看连接状态(替代 netstat)
1 | # 看监听端口的全连接队列(Recv-Q 是当前排队数,Send-Q 是队列上限) |
2. netstat -s —— 看协议栈统计
1 | # 全连接队列溢出(数字在增长就是有问题) |
3. tcpdump —— 抓包
1 | # 抓指定端口,保存为文件(用 wireshark 打开分析) |
新人必记:抓包时一定要抓 所有网卡(
-i any),不要只抓 eth0。很多内部通信走 lo 网卡,只抓 eth0 会漏掉关键包。
4. tshark —— 命令行分析抓包
1 | # 统计每个连接的 RT |
5. 内核参数快速检查
1 | # 一键查看关键 TCP 参数 |
第四课:按现象查问题(速查表)
连不上
| 现象 | 第一步 | 第二步 |
|---|---|---|
| Connection refused | ss -lntp 看端口是否在监听 |
检查进程是否存活 |
| 超时 1s/3s/7s | netstat -s | grep listen 看队列溢出 |
抓包确认 SYN 是否被丢 |
| 偶发超时(NAT 环境) | sysctl net.ipv4.tcp_tw_recycle |
如果是 1 立即改 0 |
| 部分机器不通 | traceroute + 两端同时抓包 |
检查路由/ARP/交换机 |
连上了但是断开
| 现象 | 第一步 | 第二步 |
|---|---|---|
| Connection reset | 抓包看 RST 是谁发的 | 检查防火墙/中间设备 |
| 大量 CLOSE_WAIT | ss -tp 找到对应进程 |
检查代码是否漏了 close() |
| 服务切换后长时间不恢复 | 检查 tcp_retries2 |
调小到 5-10 |
连上了但是慢
| 现象 | 第一步 | 第二步 |
|---|---|---|
| RT 偶发 40ms 毛刺 | 抓包看是否 Delayed ACK | 设置 TCP_NODELAY |
| 传输速度上不去 | ss -ti 看 cwnd/ssthresh/rto |
检查 rmem/wmem 是否太小 |
| 速度突然下降 | 抓包看是否有重传 | 检查 RTO 是否飙到 120s |
第五课:四个真实案例(必读)
案例 1:报错说 net_write_timeout,其实是被 kill 了
迁移工具报 Consider raising value of 'net_write_timeout',调大参数无效。抓包发现 MySQL Server 在传数据途中夹带了 FIN 包,查 DB 日志发现是用户自己的监控脚本 kill 了慢查询。
教训:JDBC streaming 模式下任何连接异常都报 net_write_timeout,不要被字面意思骗了。抓包看谁先发 FIN 是铁证。
案例 2:Sysbench 性能只有预期的 10%
processlist 全是 Opening tables,调大 table_open_cache 无效。最后发现是 --tables=64 写错了(实际只有 32 张表),加上 --mysql-ignore-errors=all 把 Error 1146 全吞了。
教训:抓包能看到 Error 1146 和异常 RT(2200ms vs 正常 0.1ms),即使不知道问题在哪,抓包也能发现异常。
案例 3:数据库重启后业务 15 分钟才恢复
数据库 crash 重启后,业务长时间报错。原因是 tcp_retries2 默认 15,TCP 需要约 924 秒(15 分钟)才能感知到连接断开。
教训:内网把 tcp_retries2 改成 5-10。应用层心跳比 TCP Keepalive 更可靠。
详见:长连接黑洞
案例 4:开了 tcp_tw_recycle,NAT 下偶发连不上
服务端开了 tcp_tw_recycle,NAT 后面多台客户端的 TCP timestamp 不一致,导致 SYN 被 PAWS 校验丢弃。
教训:永远不要开 tcp_tw_recycle。4.12 内核已删除此参数。用 netstat -s | grep "time stamp" 诊断。
第六课:新人上手清单
拿到一台新机器,先跑一遍这些命令建立基线:
1 | # 1. 看内核版本(4.12 以下要特别注意 tcp_tw_recycle) |
延伸阅读
本指南的所有内容都来自团队知识库 ~/case/ 下的原始文档,想深入学习可以按以下路径:
- TCP 连接原理:
网络/就是要你懂TCP--连接和握手.md→网络/就是要你懂TCP--半连接队列和全连接队列.md - TCP 性能:
网络/就是要你懂TCP--性能和发送接收Buffer的关系.md→网络/就是要你懂TCP--最经典的TCP性能问题.md - 抓包技巧:
工具/就是要你懂抓包--WireShark之命令行版tshark.md→网络/如何从几百万个抓包中找到一个异常的包.md - 排障方法论:
网络/举三反一--从理论知识到实际问题的推导.md→网络/程序员如何学习和构建网络知识体系.md
本文由 LLM 基于 wiki 知识库自动生成,最后更新:2026-04-07