SSH速度通过ProxyCommand大大提高-但是为什么呢?


14

TL; DR版本

观看此ASCII转换该视频 -然后提出发生这种情况的任何原因。下面的文字描述提供了更多的上下文。

设置细节

  • 机器1是一台Arch Linux笔记本电脑,在其ssh上生成,并连接到运行Armbian的SBC(橙色PI Zero)。
  • SBC本身通过以太网连接到DSL路由器,并且IP为192.168.1.150
  • 笔记本电脑通过Raspberry PI WiFi官方加密狗通过WiFi连接到路由器。
  • 还有另一台笔记本电脑(机器2)通过以太网连接到DSL路由器。

拓扑结构

使用iperf3对链接进行基准测试

进行基准测试时iperf3,笔记本电脑和SBC之间的链接小于理论上的56 MBits / sec,这是预期的,因为这是在“拥挤的2.4GHz” (公寓楼)内的WiFi连接。

更具体地说:在iperf3 -sSBC上运行后,在笔记本电脑上执行以下命令:

# iperf3 -c 192.168.1.150
Connecting to host 192.168.1.150, port 5201
[  5] local 192.168.1.89 port 57954 connected to 192.168.1.150 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  2.99 MBytes  25.1 Mbits/sec    0    112 KBytes       
...
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  28.0 MBytes  23.5 Mbits/sec    5             sender
[  5]   0.00-10.00  sec  27.8 MBytes  23.4 Mbits/sec                  receiver

iperf Done.

# iperf3 -c 192.168.1.150 -R
Connecting to host 192.168.1.150, port 5201
Reverse mode, remote host 192.168.1.150 is sending
[  5] local 192.168.1.89 port 57960 connected to 192.168.1.150 port 5201
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec  3.43 MBytes  28.7 Mbits/sec                  
...                
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  39.2 MBytes  32.9 Mbits/sec  375             sender
[  5]   0.00-10.00  sec  37.7 MBytes  31.6 Mbits/sec                  receiver

因此,基本上,上传到SBC的速度约为24MBits /秒,从SBC的下载速度(-R)达到32MBits /秒。

使用SSH进行基准测试

鉴于此,让我们看看SSH的价格如何。我首先经历了使用rsync和时导致这篇文章的问题borgbackup-两者都使用SSH作为传输层...所以让我们看看SSH如何在同一链接上执行:

# cat /dev/urandom | \
    pv -ptebar | \
    ssh  root@192.168.1.150 'cat >/dev/null'
20.3MiB 0:00:52 [ 315KiB/s] [ 394KiB/s]

好吧,那真是太糟糕了!比预期的链接速度慢得多... (如果您不知道pv -ptevar:它显示通过它的当前数据速率和平均数据速率。在这种情况下,我们看到/dev/urandom通过SSH 读取数据并将数据发送到SBC平均达到400KB / s,即3.2MBits /秒,远低于预期的24MBits /秒。)

为什么我们的链接以其容量的13%运行?

也许是我们/dev/urandom的错?

# cat /dev/urandom | pv -ptebar > /dev/null
834MiB 0:00:04 [ 216MiB/s] [ 208MiB/s]

不,绝对不是。

也许是SBC本身?也许处理太慢了?让我们尝试运行相同的SSH命令(即,将数据发送到SBC),但是这次是从另一台通过以太网连接的机器(机器2)上进行的:

# cat /dev/urandom | \
    pv -ptebar | \
    ssh  root@192.168.1.150 'cat >/dev/null'
240MiB 0:00:31 [10.7MiB/s] [7.69MiB/s] 

否,这可以正常工作-SBC上的SSH守护程序可以(轻松)处理其以太网链路提供的11MBytes / sec(即100MBits / sec)。

这样做时是否已加载SBC的CPU?

CPU很容易处理

不。

所以...

  • 从网络角度(按照iperf3),我们应该能够将速度提高10倍
  • 我们的CPU可以轻松承受负载
  • ...并且我们不涉及任何其他类型的I / O(例如驱动器)。

到底发生了什么事?

Netcat和ProxyCommand进行救援

让我们尝试简单的旧netcat连接-它们是否以我们期望的速度运行?

在SBC中:

# nc -l -p 9988 | pv -ptebar > /dev/null

在笔记本电脑中:

# cat /dev/urandom | pv -ptebar | nc 192.168.1.150 9988
117MiB 0:00:33 [3.82MiB/s] [3.57MiB/s] 

有用!并以预期的速度(好得多,好十倍)运行。

那么,如果我使用ProxyCommand来运行nc来运行SSH,会发生什么?

# cat /dev/urandom | \
    pv -ptebar | \
    ssh -o "Proxycommand nc %h %p" root@192.168.1.150 'cat >/dev/null'
101MiB 0:00:30 [3.38MiB/s] [3.33MiB/s]

作品!10倍速度。

现在我有点困惑-当使用“裸” nc作为时Proxycommand,您基本上不是在做与SSH完全相同的事情吗?即创建一个套接字,连接到SBC的端口22,然后通过它铲除SSH协议?

为什么最终的速度会有如此巨大的差异?

PS:这不是学术活动,因此我的borg备份运行速度提高了10倍。我只是不知道为什么:-)

编辑:在此处添加了该过程的“视频” 。计算从ifconfig输出发送的数据包,很明显,在这两个测试中,我们正在发送40MB的数据,并以大约30K的数据包传输它们-不使用时速度要慢得多ProxyCommand


缓冲?我认为nc使用行缓冲,而ssh没有缓冲。因此(如果是这样),ssh流量涉及更多数据包。
拉尔夫·朗奎斯特(RalphRönnquist)'18年

我不是专家,但我认为Orange 0只有一个由CPU控制的USB总线,网络通过该USB总线,CPU必须通过软件创建随机数(在那种架构上没有芯片可以通过硬件),同时有ssh密码正在进行中,也许还有ssh压缩。我没有检查所有这一切,所以可能我说错了。
D'Arcy Nader

2
@ D'ArcyNader:不,恐怕您弄错了。Tbe / dev / urandom发生在笔记本电脑(x86)中-我在Machine 2与SBC进行了相同的测试,达到了最高速度(100MBits / sec),从而证明SBC在处理流量方面没有问题。仅当在便携式计算机上使用SSH时才出现问题,而当我将SSH调用(再次在便携式计算机上)更改为使用netcat时,则仍在执行dev / urandom并仍在管道化所有数据时,问题消失了。顺便说一句,单USB总线是Raspberry PI(而不是Orange PI)的问题。
ttsiodras

对不起,如果我没有帮助您。并感谢您的澄清。
D'Arcy Nader

@RalphRönnquist:导致我陷入困境的最初用例是通过rsync和borgbackup备份内容。许多工具使用SSH作为传输机制-在我的情况下,正因为如此而受苦。如果我所经历的确实是“标准” SSH行为,那么我希望向所有备份工具提交拉取请求以通过netcat ProxyCommand生成SSH将立即加快整个星球的备份速度!我不敢相信我做出了这样一个“巨大”发现:-)这里肯定还有其他事情正在发生。
ttsiodras

Answers:


14

非常感谢在评论中提出想法的人们。我经历了所有这些:

使用tcpdump记录数据包并比较WireShark中的内容

# tcpdump -i wlan0 -w good.ssh & \
     cat signature | ssh -o "ProxyCommand nc %h %p" \
        root@192.168.1.150 'cat | md5sum' ; \
     killall tcpdump
# tcpdump -i wlan0 -w bad.ssh & \
     cat signature | ssh root@192.168.1.150 'cat | md5sum' ; \
     killall tcpdump

记录的数据包中没有任何重要性的差异。

检查流量整形

对此一无所知-但在查看了“ tc”联机帮助页后,我得以验证

  • tc filter show 什么都不返回
  • tc class show 什么都不返回
  • tc qdisc show

...返回这些:

qdisc noqueue 0: dev lo root refcnt 2
qdisc noqueue 0: dev docker0 root refcnt 2
qdisc fq_codel 0: dev wlan0 root refcnt 2 limit 10240p flows 1024 quantum 1514 target 5.0ms interval 100.0ms memory_limit 32Mb ecn 

...似乎没有区分“ ssh”和“ nc”的事实-实际上,我什至不确定流量整形是否可以在进程级别上运行(我希望它可以在地址/端口/区分地址上运行) IP标头中的“服务”字段)。

Debian Chroot,以避免在Arch Linux SSH客户端中潜在的“聪明”

不,相同的结果。

最后-Nagle

在发送者中执行跟踪...

pv data | strace -T -ttt -f ssh 192.168.1.150 'cat | md5sum' 2>bad.log

...查看一下传输数据的套接字上到底发生了什么,我注意到在实际传输开始之前的“设置”:

1522665534.007805 getsockopt(3, SOL_TCP, TCP_NODELAY, [0], [4]) = 0 <0.000025>
1522665534.007899 setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000021>

这将设置SSH套接字以禁用Nagle的算法。您可以在Google上阅读并了解所有内容-但这意味着SSH优先考虑带宽响应-它指示内核立即传输写在此套接字上的任何内容,而不是“延迟”等待远程的确认。

简而言之,这意味着在默认配置下,SSH并不是跨数据传输的好方法-而不是在使用的链接速度较慢时(许多WiFi链接就是这种情况)。如果我们通过“主要是报头”的空中发送数据包,则会浪费带宽!

为了证明这确实是罪魁祸首,我使用LD_PRELOAD来“删除”这个特定的系统调用:

$ cat force_nagle.c

#include <stdio.h>
#include <dlfcn.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>

int (*osetsockopt) (int socket, int level, int option_name,
           const void *option_value, socklen_t option_len) = NULL;

int setsockopt(int socket, int level, int option_name,
           const void *option_value, socklen_t option_len)
{
    int ret;
    if (!osetsockopt) {
        osetsockopt = dlsym(RTLD_NEXT, "setsockopt");
    }

    if (option_name == TCP_NODELAY) {
        puts("No, Mr Nagle stays.");
        return 0;
    }
    ret = osetsockopt(socket, level, option_name, option_value, option_len);
    return ret;
}

$ gcc -fPIC -D_GNU_SOURCE -shared -o force_nagle.so force_nagle.c -ldl

$ pv /dev/shm/data | LD_PRELOAD=./force_nagle.so ssh root@192.168.1.150 'cat >/dev/null'
No, Mr Nagle stays.
No, Mr Nagle stays.
 100MiB 0:00:29 [3.38MiB/s] [3.38MiB/s] [================================>] 100%   

那里-完美的速度(嗯,和iperf3一样快)。

故事的士气

永不放弃 :-)

而且,如果您确实使用过类似工具rsyncborgbackup通过SSH传输其数据的工具,而您的链接速度很慢,请尝试停止SSH禁用Nagle(如上所示)-或使用ProxyCommand来切换SSH以通过进行连接nc。这可以在$ HOME / .ssh / config中自动执行:

$ cat .ssh/config
...
Host orangepi
    Hostname 192.168.1.150
    User root
    Port 22
    # Compression no
    # Cipher None
    ProxyCommand nc %h %p
...

...以便将来将“ orangepi”用作ssh / rsync / borgbackup中的目标主机时,将全部nc用于连接(并因此保留Nagle)。


谢谢,您救了我的命!您是否尝试过与ssh人员联系以了解为什么没有设置来控制它?
static_rtti

1
很高兴我的发现也对您有所帮助!至于联系SSH人士,我尝试了,是的-但最终没有任何反应:bugzilla.mindrot.org/show_bug.cgi?
id=2848

将自己添加到该错误中。谁知道,最终可能会发生什么!无论如何,都要进行认真的调查。
static_rtti
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.