我有一个巨大的 rsync 任务,我想同步我的工作站和远程服务器的文件集合(通过 ssh 进行 rsync)。我估计整个过程需要数周时间,所以我不想通过增加所有其他进程的网络延迟来使我的网络一直瘫痪。
我知道如果我可以说服 rsync 切换到低优先级拥塞控制(lp
),它会在发生任何拥塞时自动将大部分网络带宽提供给其他进程。
我知道我只需运行即可加载对低优先级拥塞控制的支持,sudo modprobe tcp_lp
并且只要它在中列出,用户模式应用程序就可以使用它/proc/sys/net/ipv4/tcp_allowed_congestion_control
。
但是,我更喜欢保留cdg
或vegas
作为我的默认拥塞控制算法。如何让rsync
(以及底层ssh
)改用拥塞控制算法lp
?
rsync
我的目的是只要网络不用于任何用途就允许全速运行。
答案1
如果已知目的地,则将拥塞控制算法指定为路由选项:
ip route add <ip_addr>/32 via <gateway> congctl lp
或者,LD_PRELOAD 一个在连接之前调用 TCP 套接字的库setsockopt(..., TCP_CONGESTION, "lp")
(可能一个好的地方是通过挂钩 ssh 已经执行的现有 setsockopt(IP_TOS)调用),或者修补程序ssh
本身来执行此操作。
/* gcc -shared -o force_lp.so force_lp.c */
#define _GNU_SOURCE
#include <dlfcn.h>
#include <err.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
int setsockopt(int fd, int level, int name, const void *value, socklen_t len)
{
static int (*real_setsockopt)(int, int, int, const void *, socklen_t);
int r;
if (!real_setsockopt)
real_setsockopt = dlsym(RTLD_NEXT, "setsockopt");
if ((level == SOL_IP && name == IP_TOS) ||
(level == SOL_IPV6 && name == IPV6_TCLASS))
{
/* This is probably the TCP socket that will be used for SSH. */
r = real_setsockopt(fd, SOL_TCP, TCP_CONGESTION, "lp", sizeof "lp");
if (r != 0)
warn("Could not set congestion control algorithm");
}
return real_setsockopt(fd, level, name, value, len);
}
需要指出的是,rsync 在拥塞算法中没有发言权,因为它从未直接访问 TCP 套接字 - 它ssh
通过 stdio 与进程对话来完成所有操作。