1

我正在努力解决这个问题,任何帮助将不胜感激!

我有两个 Rails 应用程序,我们称它们为 Client 和 Service,都非常简单,普通的 REST 接口 - 这是基本场景:

  • 客户端向服务发出 POST /resources.json 请求
  • 服务运行一个创建资源并向客户端返回 ID 的进程

同样,一切都非常简单,只是服务处理非常耗时,可能需要几分钟。如果发生这种情况,客户端会在请求发出 60 秒后引发 EOFError(无论 ActiveResource::Base.timeout 设置为什么),同时服务正确处理请求并以 200/201 响应。这是我们在日志中看到的(按时间顺序):

C 00:00:00: POST /resources.json
S 00:00:00: Received POST /resources.json => resources#create
C 00:01:00: EOFError: end of file reached
  /usr/ruby1.8.7/lib/ruby/1.8/net/protocol.rb:135:in `sysread'
  /usr/ruby1.8.7/lib/ruby/1.8/net/protocol.rb:135:in `rbuf_fill'
  /usr/ruby1.8.7/lib/ruby/1.8/timeout.rb:62:in `timeout'
  ...
S 00:02:23: Response POST /resources.json, 201, after 143s

显然,服务响应从未到达客户端。我将错误追溯到套接字级别,并在脚本中重新创建了该场景,在该脚本中我打开了一个 TCPSocket 并尝试检索数据。由于我没有请求任何东西,我不应该得到任何东西,我的请求应该在 70 秒后超时(参见底部的完整脚本):

Timeout::timeout(70) { TCPSocket.open(domain, 80).sysread(16384) }

这些是一些域的结果:

www.amazon.com     => Timeout after 70s
github.com         => EOFError after 60s
www.nytimes.com    => Timeout after 70s
www.mozilla.org    => EOFError after 13s
www.googlelabs.com => Timeout after 70s
maps.google.com    => Timeout after 70s

如您所见,一些服务器允许我们“等待”整整 70 秒,而其他服务器终止了我们的连接,引发了 EOFErrors。当我们对我们的服务进行此测试时,我们(预期)在 60 秒后收到 EOFError。

有谁知道为什么会这样?有什么办法可以防止这些或延长服务器端超时?由于我们的服务继续“工作”,即使在套接字关闭后,我认为它必须在代理级别终止?

每一个提示将不胜感激!

PS:完整脚本:

require 'socket'
require 'benchmark'
require 'timeout'

def test_socket(domain)
  puts "Connecting to #{domain}"
  message = nil
  time    = Benchmark.realtime do
    begin
      Timeout::timeout(70) { TCPSocket.open(domain, 80).sysread(16384) }
      message = "Successfully received data" # Should never happen
    rescue => e
      message = "Server terminated connection: #{e.class} #{e.message}"
    rescue Timeout::Error
      message = "Controlled client-side timeout"
    end
  end
  puts "  #{message} after #{time.round}s"
end

test_socket 'www.amazon.com'
test_socket 'github.com'
test_socket 'www.nytimes.com'
test_socket 'www.mozilla.org'
test_socket 'www.googlelabs.com'
test_socket 'maps.google.com'
4

2 回答 2

2

我知道这已经快一年了,但如果其他人发现这个,我想添加一个可能的罪魁祸首。

亚马逊的 ELB 会在 60 秒后终止空闲连接,所以如果你在 ELB 后面使用 EC2,那么 ELB 可能是服务器端的问题。

于 2012-05-24T21:04:03.500 回答
0

每个服务器决定何时关闭连接。这取决于服务器端软件及其设置。你无法控制它。

于 2011-06-12T12:14:39.160 回答