我试图限制正在运行的 ruby 进程可用的带宽,以防止它淹没我们的链接并影响其他流量。该过程正在通过 HTTP 下载大文件。
我发现很多人建议trickle
作为一个方便的仅用户态选项(例如https://unix.stackexchange.com/a/34123/160146)。
我已经用 scp 下载对其进行了测试,并确认它限制了下载速率:
trickle -s -d 50 scp [email protected] localfile.dat
我还测试了 python 2.7 脚本并确认它限制了下载速率:
# cat test.py
import urllib
testfile = urllib.URLopener()
testfile.retrieve("http://example.com/bigfile.dat")
# trickle -s -d 50 python test.py
最后,我用基本的 ruby 脚本进行了测试,trickle 没有效果。这些脚本使我的下游带宽达到最大:
# cat test.rb
require 'net/http'
Net::HTTP.get_response(URI.parse("http://example.com/bigfile.dat"))
# trickle -s -d 50 ruby test.rb
我已经用 ruby 2.1、2.2 和 2.3 进行了测试,行为没有差异。
我注意到trickle文档说它只适用于动态链接的程序,但我相当确定这对我来说就是这种情况。我在 中使用 Debian 提供的 ruby /usr/bin
,并ldd
报告链接库:
# ldd /usr/bin/ruby2.3
linux-vdso.so.1 (0x00007fffdcdc6000)
libruby-2.3.so.2.3 => /usr/lib/x86_64-linux-gnu/libruby-2.3.so.2.3 (0x00007f277e11a000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f277defd000)
libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f277dc79000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f277da75000)
libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f277d83e000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f277d538000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f277d194000)
/lib64/ld-linux-x86-64.so.2 (0x0000558796396000)
有趣的是,如果我使用遏制(libcurl 绑定)gem,trickle 可以限制我的 ruby 进程的速率:
# cat test.rb
require 'curb'
http = Curl.get("http://example.com/bigfile.dat"))
# trickle -s -d 50 ruby test.rb
这是否表明 ruby 的默认Net::HTTP
库以与trickle 不兼容的方式使用套接字?
我没主意了。是否有一个固定的原因为什么trickle不能与ruby一起工作,或者我可以做些什么来让它们一起工作?
答案1
我相信我已经找到了这一点。这可以说是trickle
由于以下原因而发生的错误蠕动的特征主义在socket()
图书馆的电话里。
如您所知,代码trickle
重新定义了。socket()
在文件中重新实现的顶部trickle-overload.c
有一个检查,其中包括type == SOCK_STREAM
以便只有类型的连接SOCK_STREAM
才有资格进行处理。
该ruby
代码使用 来打开套接字type = SOCK_STREAM | SOCK_CLOEXEC
。这SOCK_CLOEXEC
是一个 Linux 扩展(自 2.6.27 起),可以避免使用后续fcntl
调用来设置 close-on-exec 标志。
不幸的SOCK_STREAM
是,与 不同,SOCK_STREAM | SOCK_CLOEXEC
因此trickle
在修复其代码以允许socket
'type
字段内现在允许的扩展之前,不会进行处理。
trickle
除了使用修改后的套接字类型比较重新编译您的系统之外,我知道没有其他解决方法。
(我已经提交了错误报告Debian Bugs,因为那是我的首选平台。)