增加 AWS Linux 上 RestClient / Net::HTTP 中的连接 (2) 超时
Increase connect(2) timeout in RestClient / Net::HTTP on AWS Linux
我正在使用 rest-client 到 POST 一个非常慢的网络服务。我将 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的超时参数只能缩短,不能延长。有没有办法修改套接字参数以设置更长的超时时间?
编辑添加: 这似乎只是我们的 AWS Linux 服务器上的问题——在我的 MacOS 开发机器上,十分钟超时有效。我假设 MacOS/BSD 上的默认 connect()
超时时间更长,但我真的不知道。
首先,您可以增加 tcp_syn_retries
configuration updating the /proc/sys/net/ipv4/tcp_syn_retries
file. Reference here。
如果不起作用,我认为您需要激活 SO_KEEPALIVE
或 TCP_USER_TIMEOUT
选项。但在 rest-client
.
中可能没有该接口
因此,您可能需要制作一个叉子或自己创建 Socket
and Socket::Option
。
Mike Perham 在他的 blog.
中写道
也许您正在摆脱套接字。套接字需要一些时间才能再次可用,如果您在短时间内打开许多连接,这可能就是问题所在。
检查ulimit -n
检查打开的文件描述符的最大数量。请记住套接字是一个文件,您需要更改它以允许打开更多套接字。要更改最大打开文件数,请执行 sudo ulimit -n 1000000
.
有关详细信息,请查看 this。
不确定 2m
限制,但 AWS NAT 有 350s
timeout。我们的 sidekiq
实例遇到了同样的问题,即使我们将 http_read_timeout
设置为 15m
(对于 Lambda 调用),即使 lambda 在不到 15m
的时间内完成我们仍然收到此错误。
为了修复,我们做了两件事:
- 将
tcp_keepalive_time
setting 设置为 < 350s
- 在所有要启用的套接字上设置
SO_KEEPALIVE
对于 us,这是使用 Net::HTTP
的 AWS SDK,不 设置此选项。因为我们没有看到覆盖 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 <->
时间表示在发送下一个保活数据包之前剩余的时间。
我正在使用 rest-client 到 POST 一个非常慢的网络服务。我将 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的超时参数只能缩短,不能延长。有没有办法修改套接字参数以设置更长的超时时间?
编辑添加: 这似乎只是我们的 AWS Linux 服务器上的问题——在我的 MacOS 开发机器上,十分钟超时有效。我假设 MacOS/BSD 上的默认 connect()
超时时间更长,但我真的不知道。
首先,您可以增加 tcp_syn_retries
configuration updating the /proc/sys/net/ipv4/tcp_syn_retries
file. Reference here。
如果不起作用,我认为您需要激活 SO_KEEPALIVE
或 TCP_USER_TIMEOUT
选项。但在 rest-client
.
因此,您可能需要制作一个叉子或自己创建 Socket
and Socket::Option
。
Mike Perham 在他的 blog.
中写道也许您正在摆脱套接字。套接字需要一些时间才能再次可用,如果您在短时间内打开许多连接,这可能就是问题所在。
检查ulimit -n
检查打开的文件描述符的最大数量。请记住套接字是一个文件,您需要更改它以允许打开更多套接字。要更改最大打开文件数,请执行 sudo ulimit -n 1000000
.
有关详细信息,请查看 this。
不确定 2m
限制,但 AWS NAT 有 350s
timeout。我们的 sidekiq
实例遇到了同样的问题,即使我们将 http_read_timeout
设置为 15m
(对于 Lambda 调用),即使 lambda 在不到 15m
的时间内完成我们仍然收到此错误。
为了修复,我们做了两件事:
- 将
tcp_keepalive_time
setting 设置为< 350s
- 在所有要启用的套接字上设置
SO_KEEPALIVE
对于 us,这是使用 Net::HTTP
的 AWS SDK,不 设置此选项。因为我们没有看到覆盖 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 <->
时间表示在发送下一个保活数据包之前剩余的时间。