lsof找到的套接字,但netstat没有找到


19

我有一个应用程序快要用完文件描述符了,显然是通过打开套接字来实现的,但是我无法确切地找到这些套接字的作用。这些在lsof输出中显示为

java    9689 appuser 1010u  sock       0,5          263746675 can't identify protocol
java    9689 appuser 1011u  sock       0,5          263746676 can't identify protocol
java    9689 appuser 1012u  sock       0,5          263746677 can't identify protocol
java    9689 appuser 1014u  sock       0,5          263746678 can't identify protocol
java    9689 appuser 1015u  sock       0,5          263746679 can't identify protocol
java    9689 appuser 1016u  sock       0,5          263746681 can't identify protocol

并在/ proc / $ PID / fd中为

lrwx------ 1 appuser appuser 64 Jun 23 11:49 990 -> socket:[263732085]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 991 -> socket:[263732086]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 992 -> socket:[263735307]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 993 -> socket:[263732088]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 995 -> socket:[263735308]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 996 -> socket:[263735309]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 997 -> socket:[263745434]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 998 -> socket:[263745435]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 999 -> socket:[263745436]

但在中没有类似的输出netstat -a

这些插座是什么,我如何找出它们的作用?

编辑:我已经尝试过运行grep $SOCKET /proc/net,如lsof FAQ中的建议 ,其中$ SOCKET例如263746679,但这也没有给出结果。


作为背景,该应用程序是多个任务的容器,这些任务尤其执行网络调用。我需要挑出一个发疯的东西,但是直到我发现那些套接字与谁通信为止,我还是被卡住了。


最近,我们的一个.NET Core Web应用程序(带有Kestrel的Ubuntu服务器)也遇到了此问题,但是记录的设备为“ 0,9”,名称为“ protocol:TCP”。事实证明,要找出确切的设备0和9是困难的。但是这些症状看起来就像是在没有绑定和使用插座的情况下打开插座的情况一样。
icelava

Answers:


17

如果创建套接字,但绝不使用它进行connect()或bind(),则可能发生这种情况。最好的选择是跟踪(-fF)应用程序,然后与lsof的输出进行交叉引用以确定哪个套接字导致了问题。作为调试的一种额外方法:如果将套接字调用与调试信息一起包装,并将其写到/ dev / null,它将显示在strace中,而不会给您带来大的日志文件。


谢谢,这听起来很有趣。我将尝试找出我们的应用程序是否确实如此。
罗伯特·蒙提亚努

1
差不多,因为这是Java,很难使用strace。更好的方法可能是创建自己的套接字子类,该子类在将信息传递给父(真实)JDK套接字之前记录信息。strace只能看到对操作系统的底层Java调用,而看不到线程内部实际上是在进行那些套接字调用的内容,因此strace看起来就像是一大堆Java。
troyengel

@troyengel:我(重新)发现了Byteman(jboss.org/byteman)一个非常整洁的工具,它使我可以注入跟踪这些调用所需的字节码。
罗伯特·蒙蒂亚努

最有用的答案,因此得到了赏金。谢谢!
罗伯特·蒙蒂亚努

2

使用Python,我在SSL套接字上遇到了相同的问题:

  • 当我使用socket.close()时,套接字会无限期地处于CLOSE_WAIT状态
  • 当我使用socket.shutdown()时,lsof说“无法识别协议”

解决方案是在关闭之前解开SSL层:

  • origsock = socket.unwrap()
  • origsock.close()

这样可以正确关闭我的应用程序中的套接字。


1

如果您的文件描述符限制,我会做的第一件事是:

~# vi /etc/sysctl.conf
fs.file-max = 331287

接下来,我将确保您的系统是最新的,其中包括所有库和服务器。您的Java应用程序服务器可能已过期(如果使用的是一台)。您的应用程序服务器配置错误的可能性也很大,您应该查看配置文件并降低您connectionTimeout和/或您的maxKeepAliveRequests(我不确定您使用的是哪个应用程序服务器,或者您是否正在使用一个...)。

我不确定该应用程序的功能,但是如果您不认为它需要成千上万个套接字,那么这几乎肯定是Java应用程序中的“文件描述符泄漏”。您可能必须将错误报告发送给供应商。在此错误报告中,您应包括有关如何重新创建问题的信息。

以下是一些调试问题的方法。

Wireshark(或cli中的twireshark)是查看这些套接字如何使用的最佳工具。Wireshark将使您详细了解通过网络抛出的流量类型。前几个连接可能会成功,然后达到文件描述符限制。一旦达到文件描述符限制,Wireshark就不会采取任何措施(对于这种情况,netstat更为整洁),但这将有助于缩小问题的范围。在某些情况下,可能发送了许多传出的SYN,但是没有接收到SYN / ACK,因此许多tcp连接只是停留在SYN_WAIT状态。

如果您可以访问源代码并且知道要创建的套接字的类型(例如使用strace或仅搜索代码),则可以在Eclipse(或另一个IDE)中打开项目,并在该函数处设置断点正在创建这些套接字。遇到断点时,您可以查看堆栈跟踪。该文件描述符泄漏可能是一个简单的无限循环,或者套接字超时值太大。另一种可能是Java应用程序没有执行socket.close()清理连接的操作。关闭通常是在a finely块中完成的try/catch(是的,在Java中套接字必须始终具有try / catch,否则它不会生成:)。最终,Java应用程序可能无法正确处理其IOException。


感谢您的回答。我实际上是在开发这个应用程序-容器部分-而不是仅仅管理它,而我找不到与未关闭套接字有关的任何问题。但是wireshark / twireshark提示很好,我会用它。
罗伯特·蒙提亚努

@Robert Munteanu如果您正在构建此应用程序,那么这是stackoverflow的问题。切勿打开太多插座。
Rook

Rook:我放弃了在代码方面找到答案的方法,并试图以sysadmin的身份进行跟踪。这就是为什么我在SF上发布。是的,我知道某种方式打开了太多的套接字。但是关于哪里...零线索...
罗伯特·蒙泰努

@Robert Munteanu您必须在创建套接字时设置断点,并查看该时刻的堆栈跟踪和内存。我怀疑您陷入无限循环。能够查看任何变量并逐步执行代码将是解决此类复杂问题的最佳方法。
Rook

不幸的是,Rook似乎随机出现在20台服务器之一上-并不总是相同-仅发生在生产环境中,并且可能每周两次。否则,伸出手指就很简单了。我目前正在使用Byteman(jboss.org/byteman)来跟踪套接字创建/绑定/连接/关闭调用。希望会有一些结果。
罗伯特·蒙提亚努
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.