Trickle无法调整我的Python脚本上传带宽

3 投票
2 回答
1799 浏览
提问于 2025-04-18 01:16

我有一个非常简单的Python脚本,叫做flickr.py,它可以把文件上传到Flickr上。它的代码大概是这样的:

#!/usr/bin/python
import sys
import os.path
import flickr_api
KEY = '<key>'
SECRET = '<secret>'
filename = sys.argv[1]
basename = os.path.basename(filename)
flickr_api.set_keys(api_key=KEY, api_secret=SECRET)
flickr_api.set_auth_handler('/home/pi/.flickr/token')
flickr_api.upload(photo_file=filename, title=basename)

这个脚本运行得很好。我只需要输入 flickr photo.jpg,照片就会出现在我的Flickr页面上。

不过,我想限制上传速度,这样我就可以在后台运行它,而不会对其他网络流量造成太大影响。所以我尝试运行...

trickle -s -u 10 flickr photo.jpg

... 可惜的是,这个命令似乎没有把上传速度限制到10kbps,正如我希望的那样。我在另一个窗口打开了NetHogs来测试,结果上传速度直接飙到了80kbps,就像我没有使用 trickle 一样。

我尝试了各种方法,比如以超级用户身份运行,或者在命令前加上Python解释器的完整路径(trickle -s -u 10 /usr/bin/python flickr photo.jpg)。但都没有效果。

我还用 trickle 测试了其他程序,比如 wgetscp,结果都如预期那样工作。那我到底漏掉了什么呢?

可能相关的说明:我是在树莓派上进行的测试。

更新:我使用的Flickr API模块是这个...

https://github.com/alexis-mignon/python-flickr-api

... 不过我刚刚用这个模块重写了我的示例 ...

http://stuvel.eu/flickrapi

... 结果还是一样。

2 个回答

0

你在用哪个操作系统?我知道Ubuntu(至少是18.04和20.04)的trickle软件包缺少一些上游的修复,比如这个链接中的内容:https://github.com/mariusae/trickle/commit/bb2825a1fe938e303acd5d65508476ca03961d85

我建议你从源代码编译trickle,然后再试一次。

这个特别的修复会解决与python3相关的问题。显然,python2不使用SOCK_CLOEXECSOCK_NONBLOCK,所以它不受影响。

2

简要概述

原帖中的问题在相同的硬件上无法重现,因此我认为可能是对单位的误解(10 KB/s == 80 kbps)。一个类似但不完全相同的问题引发了对这个问题的悬赏,所以我提供了一些诊断技巧。我将回答分成几个部分:

  1. 原始问题
  2. 诊断步骤建议
  3. 关于使用 awscli 可能出现的问题的假设

1. 原始问题(无法重现)

我用 Raspbian 操作系统(没有图形界面)设置了一个 Raspberry Pi,安装了与原帖相同的库(都是用 sudo 来加快速度...)

sudo pip install flickr_api
sudo apt-get install nethogs
sudo apt-get trickle

接下来,你需要注册一个 Flickr 账户,创建一个(非商业)应用,并设置 API 密钥等 - 创建应用的说明在这里,获取 API 密钥的说明在这里,或者通过 Python 包装器在这里

我找到了一张 1.9MB 的图片,命名为 test.jpg,然后尝试了以下操作:

  1. /usr/bin/python flickr.py test.jpg
  2. trickle -s -u 10 /usr/bin/python flickr.py photo.jpg

结果

  1. 图片上传大约用了 3 秒,nethogs 显示上传速度峰值约为 400KB/s
  2. 图片上传超过了一分钟,nethogs 显示上传速率短暂达到 13 KB/s(然后稳定在 10.081)。

一切正常

因此,我认为原帖的问题简单来说就是:trickle 中的上传限制是以千字节每秒(kB/s)设置的,而原帖作者可能是以千比特每秒(kbps)来读取速度的。所以有 8 倍的差异。


2. 不过...类似问题的诊断

@James_pic 在这个问题上发布了悬赏,结果发现他的情况与原帖并不相同。特别是,他在使用aws-cli 上传到亚马逊云服务时没有遇到限制。

既然如此,我将发布一些进一步的诊断方法。这篇论文描述了 trickle 的工作原理,并描述了几个 trickle 无法工作的场景:

  1. 当用户没有自愿在 trickle 下运行时
  2. 其次,影响较小,Trickle 无法与静态链接的二进制文件一起工作。

可能第二种情况在这里相关,所以我将概述一种你可以开始诊断的方法,使用strace。这个网站上还有另一个问题讨论strace 的一般用法和具体用法,查看正在使用的共享库在这里

由于我没有关于 aws-cli 的可重现示例,我将展示我在 flickr_api 案例中验证操作时所做的。

根据手册,strace

拦截并记录进程调用的系统调用和接收到的信号。由于我们正在调查使用的系统库,我们对 open 消息感兴趣,因此我使用了以下命令,实际上是用 strace 包装上面的命令,然后筛选输出中的 open

  1. strace /usr/bin/python flickr.py test.jpg 2>&1 | grep open > strace.out
  2. strace trickle -s -u 10 /usr/bin/python flickr.py test.jpg | grep open > strace_with_trickle.out

最后,我对这两个文件进行了比较:

diff strace_with_trickle.out strace.out

不出所料,使用 trickle 的版本输出了更多的行 - 特别是这些:

< open("/lib/arm-linux-gnueabihf/libbsd.so.0", O_RDONLY) = 3
< open("/lib/arm-linux-gnueabihf/libc.so.6", O_RDONLY) = 3
< open("/lib/arm-linux-gnueabihf/libgcc_s.so.1", O_RDONLY) = 3
< open("/usr/lib/trickle/trickle-overload.so", O_RDONLY) = 3
< open("/etc/ld.so.preload", O_RDONLY)    = 3
< open("/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so", O_RDONLY) = 3
< open("/etc/ld.so.cache", O_RDONLY)      = 3

这些行涵盖了在运行进程时 trickle-overload.so 的插入情况。特别是,我们可以观察到标准的套接字库正在使用并动态加载 - 即 libc.so.6libbsd.so.0,这让我们对 trickle 应该能正常工作有了一定的信心。

这个技术是相当通用的 - 使用一个正常工作的案例和一个不工作的案例,然后对输出进行 diff 比较,应该能让你更进一步。


3. 最后... awscli 的假设

我怀疑 awscli 可能在上传过程中会生成新的进程。如果是这样的话,我认为 trickle 使用 -s 选项将无法限制这些子进程。你可以在守护进程模式下使用它 - 这可能效果更好 - 你可以通过输入 man trickled 来查看如何操作。

本质上 - 你首先启动守护进程,例如:

trickled -u 10

然后“订阅”进程,例如:

trickle /usr/bin/python flickr.py test.jpg

注意 我没有关于 awscli 问题的可重现测试案例,所以这只是推测。

撰写回答