我们偶尔会遇到奇怪的网络堆栈问题,但这种情况并不常见。重新启动相关服务器即可解决问题。
事情发生如下(从tcpdump
服务器上收集到):
HTTP 客户端开始向 Nginx 发送请求。
服务器正常响应,确认收到的每个数据包。
在最终的客户端发送,数据包永远不会到达服务器上的接收套接字。
客户端多次重新发送数据包,最终服务器超时并断开连接。
此外,strace
Nginx 确认数据是不是到达 Nginx。
这里这是输出的编辑版本tcpdump
。我简化了交流并匿名化了一些细节。
打开 iptables 日志记录显示一些数据包被阻止,这可能相关:
IN= OUT=lo SRC=client DST=server LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=39670 DPT=80 WINDOW=0 RES=0x00 RST URGP=0
IN= OUT=eth0 SRC=server DST=client LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=80 DPT=39669 WINDOW=31 RES=0x00 ACK URGP=0
但是,我们的 iptables 设置很普通。我们阻止除 之外的所有内容RELATED,ESTABLISHED
,并允许有问题的端口 80。我不明白为什么 iptables 会阻止这一点,除非数据包不知何故超出了RELATED
和的状态ESTABLISHED
。
我还在sysctl
上面的要点中包含了我们的设置。还有什么我可以看看的吗?
DigitalOcean 上的 Ubuntu 12.04.3 上的 Linux 3.8.0。
编辑3:禁用 iptables,同样的问题,所以这不是由错误的 iptables 规则引起的。
编辑2:上面我展示了 iptables 阻止RST
数据包,但更重要的是它阻止了很多ACK
数据包。我只是挑选了一个随机日志条目,ACK
似乎更常见。
编辑1:我添加了 iptables 跟踪。这似乎是丢弃数据包的部分(不过,再次不确定这是否与我的问题有关):
TRACE: raw:OUTPUT:rule:2 IN= OUT=lo SRC=client DST=server LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=41572 DPT=8001 SEQ=2118637628 ACK=0 WINDOW=0 RES=0x00 RST URGP=0
TRACE: raw:OUTPUT:policy:3 IN= OUT=lo SRC=client DST=server LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=41572 DPT=8001 SEQ=2118637628 ACK=0 WINDOW=0 RES=0x00 RST URGP=0
TRACE: filter:OUTPUT:rule:3 IN= OUT=lo SRC=client DST=server LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=41572 DPT=8001 SEQ=2118637628 ACK=0 WINDOW=0 RES=0x00 RST URGP=0
TRACE: filter:block:rule:1 IN= OUT=lo SRC=client DST=server LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=41572 DPT=8001 SEQ=2118637628 ACK=0 WINDOW=0 RES=0x00 RST URGP=0
TRACE: filter:logging:rule:1 IN= OUT=lo SRC=client DST=server LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=41572 DPT=8001 SEQ=2118637628 ACK=0 WINDOW=0 RES=0x00 RST URGP=0
iptables: reject: IN= OUT=lo SRC=client DST=server LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=41572 DPT=8001 WINDOW=0 RES=0x00 RST URGP=0
不知道lo
这里为什么会涉及此问题。服务器正在接受流量eth0
。
答案1
您的日志确实显示了lo
接口上正在发生的通信。
iptables
通过将INPUT
表默认策略更改为来禁用ACCEPT
并停用任何可能妨碍的REJECT
或规则DROP
- 再次测试并检查它是否正常工作。如果没有,则问题出在其他地方
我敢打赌 1000 美元,你的接受流量的过滤规则与某个eth0
接口绑定,从而拒绝传入的流量lo
。
我会注意测试客户端与服务器的关系。如果您在同一台机器上运行测试客户端,它很可能使用 IP127.0.0.1
地址或localhost
通常解析为同一 IP 地址的域名。
这样将会在特殊的环回接口(lo
)上发送流量,而不是在那个接口上发送eth0
。
除非您通过要求 nginx 监听其 IP 地址将 nginx 绑定到特定接口,否则 nginx 将默认监听0.0.0.0
,即每个接口。因此,您不会注意到它是否接受连接lo
。您可以尝试强制 nginx 监听您的eth0
IP 地址以确保万无一失。
在本地测试您的服务器时,请确保使用您的一个外部接口(eth[0..]
)IP 地址,或解析为其中一个接口的域名。