在 AWS Linux 上增加 RestClient / Net::HTTP 中的 connect(2) 超时

Posted

技术标签:

【中文标题】在 AWS Linux 上增加 RestClient / Net::HTTP 中的 connect(2) 超时【英文标题】:Increase connect(2) timeout in RestClient / Net::HTTP on AWS Linux 【发布时间】:2017-03-28 18:36:23 【问题描述】:

我正在使用rest-client 发布到一个非常慢的网络服务。我将 timeout 设置为 600 秒,并且我已经确认它正在传递给 Net::HTTP 的 @read_timeout@open_timeout

但是,大约两分钟后,我收到一个低级超时错误,Errno::ETIMEDOUT: Connection timed out - connect(2)

回溯的相关部分是

Operation timed out - connect(2) for [myhost] port [myport]
/Users/dmoles/.rvm/rubies/ruby-2.2.5/lib/ruby/2.2.0/net/http.rb:879:in `initialize'
/Users/dmoles/.rvm/rubies/ruby-2.2.5/lib/ruby/2.2.0/net/http.rb:879:in `open'
/Users/dmoles/.rvm/rubies/ruby-2.2.5/lib/ruby/2.2.0/net/http.rb:879:in `block in connect'
/Users/dmoles/.rvm/rubies/ruby-2.2.5/lib/ruby/2.2.0/timeout.rb:88:in `block in timeout'
/Users/dmoles/.rvm/rubies/ruby-2.2.5/lib/ruby/2.2.0/timeout.rb:98:in `call'
/Users/dmoles/.rvm/rubies/ruby-2.2.5/lib/ruby/2.2.0/timeout.rb:98:in `timeout'
/Users/dmoles/.rvm/rubies/ruby-2.2.5/lib/ruby/2.2.0/net/http.rb:878:in `connect'
/Users/dmoles/.rvm/rubies/ruby-2.2.5/lib/ruby/2.2.0/net/http.rb:863:in `do_start'
/Users/dmoles/.rvm/rubies/ruby-2.2.5/lib/ruby/2.2.0/net/http.rb:852:in `start'
/Users/dmoles/.rvm/gems/ruby-2.2.5/gems/rest-client-2.0.0/lib/restclient/request.rb:766:in `transmit'
/Users/dmoles/.rvm/gems/ruby-2.2.5/gems/rest-client-2.0.0/lib/restclient/request.rb:215:in `execute'
/Users/dmoles/.rvm/gems/ruby-2.2.5/gems/rest-client-2.0.0/lib/restclient/request.rb:52:in `execute'

看起来抛出错误的代码行是

TCPSocket.open(conn_address, conn_port, @local_host, @local_port)

似乎底层的connect(2) 系统调用有大约两分钟的超时时间,而传递给 Net::HTTP 的超时参数只能缩短它,而不是延长它。有没有办法修改socket参数设置更长的超时时间?

编辑添加:这似乎只是我们的 AWS Linux 服务器上的问题——在我的 MacOS 开发机器上,十分钟的超时有效。我假设默认的 connect() 超时在 MacOS/BSD 上更长,但我真的不知道。

【问题讨论】:

【参考方案1】:

首先,您可以增加tcp_syn_retries 配置更新/proc/sys/net/ipv4/tcp_syn_retries 文件。参考here。

如果 if 不起作用,我认为您需要激活 SO_KEEPALIVETCP_USER_TIMEOUT 选项。但是rest-client中可能没有接口。

所以也许你需要自己创建一个 fork 或 SocketSocket::Option

Mike Perham 在他的blog 中写道。

【讨论】:

【参考方案2】:

也许您正在使用套接字。套接字需要一段时间才能再次可用,如果您在短时间内打开许多连接,这可能是问题所在。

检查ulimit -n 以检查打开的文件描述符的最大数量。请记住,套接字是一个文件,您需要更改它以允许打开更多套接字。要更改打开文件的最大数量,请执行sudo ulimit -n 1000000

更多信息,请查看this。

【讨论】:

【参考方案3】:

不确定2m 的限制,但AWS NAT 有350s timeout。我们的 sidekiq 实例也遇到了同样的问题,即使我们将 http_read_timeout 设置为 15m(对于 Lambda 调用),即使 lambda 在不到 15m 的时间内完成,我们仍然会收到此错误。

为了解决这个问题,我们做了两件事:

tcp_keepalive_time setting 设置为< 350s 在所有要启用的套接字上设置SO_KEEPALIVE

对于 us,这是使用 Net::HTTP 的 AWS 开发工具包,没有设置此选项。因为我们没有看到覆盖 AWS v3 SDK 的 HTTP 适配器的方法,所以我们在初始化程序中被降级为:

module KeepAliveAwareNetHttp
  def on_connect
    @socket.io.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
    super
  end
end

Net::HTTP.prepend(KeepAliveAwareNetHttp)

为了在您的服务器上验证这一点(查看是否有任何 TCP 套接字具有此设置)您可以运行 ss -te。如果有一个启用了此功能的套接字,它将看起来像这样:

ESTAB   0         0                171.190.0.6:53254        100.80.12.28:5432     timer:(keepalive,3min11sec,0) ino:113741 sk:90 <->

时间表示在发送下一个保持活动数据包之前剩余的时间。

【讨论】:

以上是关于在 AWS Linux 上增加 RestClient / Net::HTTP 中的 connect(2) 超时的主要内容,如果未能解决你的问题,请参考以下文章

AWS ec2 根卷增加:在 aws ubuntu 实例上扩展弹性根卷不起作用

如何在运行 AWS Linux 2 的 AWS Elastic Beanstalk 上配置 Linux 交换空间?

如何在 Amazon AWS 上设置一台 Linux 服务器

sh [在AWS EC2 Linux服务器上从PHP 5.X.X升级到PHP 7] #linux #aws

AWS Elastic Beanstalk - 增加实例磁盘容量

如何在 AWS EC2 Linux 2 上安装 NGINX [关闭]