从networking连接读取时,进程无限期挂起

更新如下:

我在一个不相关的脚本上经历了类似的问题,在不同的数据中心的Debian虚拟机上。

这看起来像这里描述的问题(和像问这个问题的人一样,我没有在服务器前configuration代理)。

与以下描述的主要区别在于,当我附加到挂起的进程时,我看到一个调用recvfrom而不是read

 $ strace -p 17527 Process 17527 attached - interrupt to quit recvfrom(3, 

不过Python并没有被代理的印象:

 >>> import os; print os.getenv("HTTP_PROXY"), os.getenv("http_proxy") None, None 

所以我仍然难住。 可悲的是,这个相关的问题也没有最终的答案。

(我也想知道这个问题是否是相关的,但是S3似乎不太可能不尊重Connection: close headers。)


我有几个Debian(Wheezy,x86_64)服务器都显示以下行为:

所有服务器都有一组cron作业,其中包括从S3中提取数据。 这些通常运行良好,但偶尔ps aux显示,几小时或几天前开始的一些工作仍在运行,并没有完成干净。

使用strace -p <pid>检查它们显示,在所有情况下,该进程都挂在一个读取命令上。 例如,我刚刚检查的一个进程的输出是:

 $ strace -p 12089 Process 12089 attached - interrupt to quit read(5, 

检查打开的文件描述符给了我这个:

 $ sudo lsof -i | grep 12089 python 12089 user 5u IPv4 809917771 0t0 TCP my.server.net:35427->185-201.amazon.com:https (ESTABLISHED) 

起初,我认为这只是由于缺less在Python脚本中设置读取超时的原因,但似乎并非如此,原因如下:

  1. 当我们使用相同的代码在我们的OS X机器上运行相同的工作(所有10.5,i386)时,这不会发生。
  2. 自从昨天以来,脚本的一个变体设置了超时(60秒,使用socket.setdefaulttimeout – 这是在Python 2.7中,但代码库必须兼容2.5)。
  3. 另一个不是Python的进程似乎偶尔也会出现类似的行为。 在这种情况下,Python脚本正在执行一个svn up --non-interactive进程(使用subprocess.Popen ,这是值得的)。

那个SVN过程的情况是类似的 –

Python正在等待SVN:

 $ strace -p 28034 Process 28034 attached - interrupt to quit wait4(28127, 

而SVN正在等待read电话完成:

 $ strace -p 28127 Process 28127 attached - interrupt to quit read(6, 

那读是指向另一个外部主机:

 $ sudo lsof -i | grep 28127 svn 28127 user 3u IPv4 701186417 0t0 TCP my.server.net:49299->sparrow.telecommunity.com:svn (ESTABLISHED) svn 28127 user 6u IPv4 701186439 0t0 TCP my.server.net:49309->sparrow.telecommunity.com:svn (ESTABLISHED) 

(似乎有一个svn:externals属性设置为ez_setup svn://svn.eby-sarna.com/svnroot/ez_setup在目录被更新;基于他们的网站,我认为这是redirect到telecommunity.com)

其他可能相关的要点:

  • Mac上的Python环境是2.5。 在Debian中,它是2.7。
  • 我对SVN并不熟悉,我不知道它悬挂的原因是否基本相同。 我也不完全确定svn:externals的含义是什么; 这是在我的时间之前build立的。
  • Python脚本本身正在从Amazon S3中检索大量的数据(大约10MB),而且这种情况往往会变得缓慢(我看到下载时间长达三分钟,这似乎比较长冗长的服务器 – 即使在不同的数据中心 – 也需要相互通信)。 同样,我们的一些SVN仓库相当大。 所以基本上说这些操作中的一些操作是长时间运行 ,但是在某些情况下,它们似乎也会挂起数小时或数天。
  • 在一台服务器上,OOM杀手今天早上拿出了MySQL。 内存使用率为90%,交换使用率为100%(Monit报告)。 杀死大量的Python作业,这些数据分别降低了60%和40%。 这给我的印象是,至less有一些(如果不是全部)数据被下载/读取(并且在进程挂起时保存在内存中)。
  • 这些cron作业正在请求来自S3的资源列表,并相应地更新MySQL表的列表。 每个作业都使用相同的列表启动,因此会尝试请求相同的资源并更新相同的表。
  • 我能够从一个挂起的进程中捕获一些stream量; 这对我来说有点难以理解,但是我想知道是否表示连接是活跃的并且工作正常,非常慢? 我已经提供了它作为一个要点,以避免混乱(我应该注意,这是约两个小时值得捕获): https : //gist.github.com/petronius/286484766ad8de4fe20b这是一个红色的鲱鱼,我认为。 在那个端口上有活动,但是和S3的连接不一样 – 这只是其他的随机服务器活动。
  • 我试图在另一个数据中心(运行相同系统设置的Debian相同版本的虚拟机)的盒子上重新创build这个问题,但没有运气(我想这也许是问题所在,但遇到这些问题的盒子不是虚拟机,并且根据ifconfig没有丢弃的数据包)。 我想这表明一个networkingconfiguration问题,但我不知道从哪里开始。

所以我想我的问题是:

  • 我可以在系统级别解决这个问题吗,还是每个进程都有问题?
  • 对于OS X和Linux如何处理read调用,我需要知道的以避免无限悬挂进程,有什么根本的不同吗?

我可以在系统级别解决这个问题吗,还是每个进程都有问题?

这很难说,因为它在协议层面上是未知的。 read(2)基本上将无限期地提供: –

  • TCP连接保持打开状态。
  • 您希望至less有一个字节的数据到达。
  • 发件人尚未准备好向您发送数据。

现在,这个过程可能是有问题的,比如另一端在发送更多的数据之前就要等待你的响应,或者另一端的响应预期SVN在请求更多的数据之前做其他的事情 。 假设例如一个错误响应回来,这应该强制客户端重新发送一些信息。

你不能修复这个优雅,因为它不可能的信息,你必须确定这个数据的发送者希望你做的事情。 但是,有几种可能的方法来避免这个问题并报告。

  • 而不是在简单的阻塞模式下使用wait ,运行wait并在父进程中configuration一个警报。 现在,当进程无法在一段固定的时间内完成,你可以杀死它并报告发生的事情。 一个便宜的方法是修改subprocess.Popen来调用timeout命令。
  • 修改读取,以便它设置读取超时套接字选项。 您可以通过更改代码来完成此操作,或者 – 使用插入程序来覆盖默认的socket系统调用,并为接收方添加超时。 这两个都不是微不足道的。 这可能会导致svn以意想不到的方式行事。

对于OS X和Linux如何处理读取调用,我需要知道的以避免无限悬挂进程,有什么根本的不同吗?

我不知道这个问题的答案,但是如果两者都是正确的,他们都应该以同样的方式行事。 如果您尝试从尚未准备好发送数据的套接字读取数据,则无限期地阻止数据stream是预期的行为。

总的来说,我认为你最好的select是希望你的svn命令在特定的时间内完成。 如果它不杀它,并报告你这样做。

我想我已经找出了上述的问题,而且大部分的谜团都来自于我对服务器上发生的事情的误解。

有以下基本问题:

  • Python脚本应该有一个超时设置(我认为是)没有。 当连接到S3时,其中一些无限期地挂起,performance出无限期等待读取完成的行为。 梳理代码并确保全局套接字超时被设置,并且没有被解除,似乎已经解决了这个问题。
  • 一些旧的Python进程似乎被挂起,但仔细观察(一旦真正被阻塞的进程被清除了),他们只是列出大型的S3桶来检查这些桶中的密钥的状态,并且这个操作需要几个小时或天完成。
  • SVN checkout命令在很长的时间内(仍然)挂着,当更新非常大的项目时,很多文件的目录结构很深。 客户端正在等待读取完成,但这完全是合法的(似乎要花费很长时间才能收集需要发送回客户端的数据)。

我在这里留下这个答案来解释发生了什么,但是我会接受马修的,因为他对于实际可能的问题是正确的。