【问题标题】:TCP Socket hanging - both sides stuck in sendto()TCP Socket 挂起 - 双方都卡在 sendto()
【发布时间】:2011-11-17 18:29:02
【问题描述】:

我们有一个似乎挂起的 linux 应用程序(我们没有源代码)。两个进程之间的套接字报告为 ESTABLISHED,并且内核套接字缓冲区中有一些数据(尽管远不及通过 wmem/rmem 配置的 16M)。套接字的两端似乎都卡在了 sendto() 上。

以下是使用 netstat/lsof 和 strace 进行的一些调查:

主机 A (10.152.20.28)

[root@hosta ~]# lsof -n -u df01 | grep 12959 | grep 12u
q         12959 df01   12u  IPv4            4398449                TCP 10.152.20.28:38521->10.152.20.29:gsigatekeeper (ESTABLISHED)

[root@hosta ~]# netstat -anp | grep 38521
tcp   268754  90712 10.152.20.28:38521          10.152.20.29:2119           ESTABLISHED 12959/q

[root@hosta ~]# strace -p 12959
Process 12959 attached - interrupt to quit
sendto(12, "sometext\0somecode\0More\0exJKsss"..., 542, 0, NULL, 0 <unfinished ...>
Process 12959 detached
[root@hosta~]#

主机 B (10.152.20.29)

[root@hostb ~]# netstat -anp | grep 38521
tcp    72858 110472 10.152.20.29:2119           10.152.20.28:38521          ESTABLISHED 25512/q

[root@hostb ~]# lsof -n -u df01 | grep 38521
q         25512 df01   14u  IPv4            6456715                 TCP 10.152.20.29:gsigatekeeper->10.152.20.28:38521 (ESTABLISHED)

[root@hostb ~]# strace -p 25512
Process 25512 attached - interrupt to quit
sendto(14, "\0\10\0\0\0Owner\0sym\0Type\0Ctpy\0Time\0Lo"..., 207, 0, NULL, 0 <unfinished ...>
Process 25512 detached
[root@hostb~]#

我们已将 NIC 驱动程序升级到最新最好的版本。系统运行的是 RHEL 5.6 x64 (2.6.18-238.el5),我检查了 RHEL 5.7 和 5.8 的 eratta,但我看不到 bnx2 驱动程序或内核的错误。

有人对如何进一步调试有任何想法吗?

【问题讨论】:

  • 您的系统很好,但您的应用程序已损坏。扔掉它。程序员很可能以不安全的方式进行同步 I/O,从而导致了这种死锁。
  • 一般可用空间是配置的wmem/rmem的一半,通常更少。

标签: linux sockets freeze sendto


【解决方案1】:

双方都在阅读吗?如果没有,可能是双方的接收缓冲区都满了,导致不发送数据(由于接收窗口被填满),导致双方的发送缓冲区都被填满,导致sendto阻塞。 (如果应用程序正在设置SO_RCVBUFSO_SNDBUF 套接字选项,尽管您设置了 wmem/rmem,但仍有可能发生这种情况。)

为了调试它,我会同步两台机器的时钟,然后在 strace 下运行两个应用程序,并使用 -e trace=network-tt 选项,这样您就可以比较日志并查看应用程序是否没有读取。

您还可以使用网络分析器(例如 Wireshark)来确定 TCP 接收窗口是否卡在 0。

如果是这种情况,您可能可以通过创建一个小型缓存代理来解决此问题,该代理将从双方接收/发送,缓冲当时无法发送的任何内容。

【讨论】:

  • 双方都没有阅读。它是一个单线程应用程序,并且都卡在 sendto() 上。我必须从上面的 strace 输出中删除 ^C。我不知道 strace 的网络跟踪功能,这肯定是我接下来要看的地方。我已经再次使用 strace 检查了 SO_RCV/SOSNDBUF 在创建套接字时没有设置,但事实并非如此。 rmem/wmem 设置设置为 16M,我可以使用 netperf 将 RECQ/SNDQ 几乎填满,例如:tcp 0 15570344 10.152.20.28:57385 10.152.20.29:40366 ESTABLISHED 4875/netperf
  • 我还将获取流量的 pcap,并注意窗口大小。我对窗口缩放的理解是,当两个主机位于 LFP 的末端时会有所帮助,从而导致较大的 BDP(传输中的数据)。当主机与同一局域网上的其他主机通信时,在主机上禁用窗口缩放会不会很离谱?
  • 我最终使用了 systemtap 和出色的 pfiles stap 脚本来进一步解决这个问题。强烈推荐:sourceware.org/systemtap/wiki/WSPfiles
  • @The_Viper:如果您找到解决方案,我很想听听问题所在