2. 网络层故障:节点间网络延迟与丢包、TCP连接池耗尽、DNS解析异常、防火墙策略误拦截
网络层的问题,说实话,是交易系统里最难缠的。为什么?因为它的表象千奇百怪——有时候是超时,有时候是连接被重置,有时候干脆就是卡住不动。我见过太多团队在应用层翻来覆去地查代码,最后发现是网络层面的一根网线松了。嗯,咱们今天就把这块彻底讲透。
2.1 网络延迟与丢包
先说说延迟和丢包。这两个东西经常一起出现,但本质不同。延迟是数据包在路上磨蹭,丢包是数据包直接失踪了。
延迟的影响:交易系统对延迟极其敏感。一个订单从A节点到B节点,正常情况1ms内搞定。如果延迟飙升到50ms,整个系统的吞吐量就会断崖式下跌。为什么?因为TCP的拥塞控制算法会认为网络状况不好,主动降低发送速率。
丢包的影响:丢包更致命。TCP协议会重传丢失的数据包,重传超时时间(RTO)默认是200ms起步。你想想看,一个交易请求在200ms后才被重传,对于高频交易来说,黄花菜都凉了。
核心指标参考:
| 指标 | 正常范围 | 告警阈值 | 严重阈值 |
|---|---|---|---|
| 节点间延迟 | < 1ms | > 5ms | > 20ms |
| 丢包率 | 0% | > 0.1% | > 1% |
| TCP重传率 | < 0.01% | > 0.5% | > 2% |
排查工具:我个人习惯用 mtr 命令。它结合了 ping 和 traceroute 的功能,能逐跳显示延迟和丢包率。举个例子:
# 从节点A到节点B的链路质量检查
mtr -r -c 100 10.0.1.100
# 输出示例(关键部分)
# 1. 10.0.0.1 0.3% 0.2ms
# 2. 172.16.1.1 0.0% 0.5ms
# 3. 10.0.1.100 2.1% 15.3ms ← 这里丢包了!
看到第3跳丢包2.1%,延迟15.3ms,基本可以断定是节点B的网卡或者交换机端口有问题。我在项目中遇到过类似情况,最后发现是交换机的光模块老化,换了就好了。
小技巧:用 ss -ti 可以查看每个TCP连接的RTT(往返时间)和重传情况。比 netstat 好用多了。
2.2 TCP连接池耗尽
这个问题在微服务架构里特别常见。每个服务都跟其他服务建立TCP连接,如果连接不释放,池子很快就满了。
为什么会耗尽?说白了就是三个原因:
- 连接泄漏:代码里开了连接没关闭。我见过一个案例,某团队用HTTP客户端没设置超时,结果慢请求把连接全占住了。
- 突发流量:平时1000个连接够用,突然来了10倍流量,连接池瞬间爆掉。
- TIME_WAIT堆积:主动关闭连接的一方会进入TIME_WAIT状态,默认60秒。如果每秒创建上万个连接,TIME_WAIT会堆积如山。
排查方法:先看系统级别的连接数:
# 查看当前TCP连接状态分布
ss -s
# 查看TIME_WAIT数量
ss -tan | grep TIME_WAIT | wc -l
# 查看某个端口的连接数
ss -tan | grep :8080 | wc -l
如果TIME_WAIT超过几万个,说明连接创建太频繁了。这时候我建议做两件事:
- 开启连接复用:在Linux内核参数里设置
net.ipv4.tcp_tw_reuse=1,允许复用TIME_WAIT状态的连接。 - 调整连接池大小:应用层的连接池(比如HTTP连接池、数据库连接池)要根据压测结果合理设置。我一般建议设置成
最大并发数 * 1.5。
注意:tcp_tw_reuse 只适用于客户端场景。如果是服务端,别乱开这个参数,可能会引起数据错乱。我曾经踩过这个坑,后来老老实实改代码去了。
2.3 DNS解析异常
DNS出问题,整个系统就像瞎了一样。服务发现全靠它,它一挂,所有节点都找不到彼此。
典型症状:
- 服务启动时卡在
java.net.UnknownHostException - 偶尔出现连接超时,重试后又好了
- 不同节点解析到不同的IP地址
排查步骤:
- 检查本地DNS配置:
cat /etc/resolv.conf,看看nameserver对不对。 - 测试解析速度:
dig @8.8.8.8 my-service.example.com,看响应时间。超过100ms就算慢。 - 检查缓存:用
nscd -g查看DNS缓存命中率。命中率低于90%说明缓存策略有问题。
我记得有一次线上故障,所有服务都连不上数据库。查了半天,发现是DNS服务器挂了,而应用层没有做DNS缓存。从那以后,我强制要求所有服务必须配置本地DNS缓存,并且设置合理的TTL(建议30-60秒)。
最佳实践:
- 使用
systemd-resolved或dnsmasq做本地缓存 - Java应用设置
-Dsun.net.inetaddr.ttl=30控制DNS缓存时间 - 核心服务用IP直连,绕过DNS
2.4 防火墙策略误拦截
防火墙策略,嗯,这东西是运维的噩梦。每次上线新服务,都要跟网络团队反复确认端口开没开。稍有不慎,就把正常流量给拦了。
常见场景:
- 新部署的服务端口没加入白名单
- 防火墙规则顺序不对,匹配到了拒绝规则
- 状态防火墙把长连接给断了(比如NAT超时)
排查命令:
# 检查iptables规则
iptables -L -n -v
# 检查防火墙日志(CentOS/RHEL)
grep "DPT=8080" /var/log/messages
# 用nc测试端口是否可达
nc -zv 10.0.1.100 8080
如果 nc 显示连接成功,但应用层还是报错,那可能是7层防火墙(比如WAF)在搞鬼。我遇到过WAF把包含特定关键字的交易请求当成SQL注入给拦截了,排查了整整两天才找到原因。
避坑指南:我曾经在变更防火墙规则时,忘记保存配置。结果重启后规则全丢了,生产环境裸奔了5分钟。现在我的习惯是:改规则前先 iptables-save > backup.rules,改完再 iptables-save > new.rules,对比一下差异再提交。
2.5 知识体系总览
下面这张图,是我自己总结的网络层故障排查框架。你可以把它当成一个检查清单,遇到问题按图索骥就行。
这张图把四个核心问题、对应的排查工具、以及最终的解决方案串起来了。你遇到网络层故障时,先判断属于哪一类,然后直接看对应的工具和方案就行。
总结一下:网络层故障排查,说白了就是「看指标、查工具、对方案」。延迟丢包看mtr,连接池看ss,DNS看dig,防火墙看iptables。把这四个工具用熟了,80%的网络问题都能快速定位。
最后说一句:别光靠工具,还要理解原理。比如TCP的拥塞控制、TIME_WAIT的状态机、DNS的递归查询流程——这些底层知识,才是你真正能快速定位问题的底气。
公众号:蓝海资料掘金营,微信deep3321