为什么 ruby​​ 中的涓流速率限制不起作用?

为什么 ruby​​ 中的涓流速率限制不起作用?

我试图限制正在运行的 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,因为那是我的首选平台。)

相关内容