首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过ProxyCommand,SSH的速度有了很大的提高,但为什么呢?

通过ProxyCommand,SSH的速度有了很大的提高,但为什么呢?
EN

Unix & Linux用户
提问于 2018-04-01 12:03:06
回答 1查看 5.5K关注 0票数 19

The TL;DR版本

看这个ASCII的演员阵容这段视频 --然后想出发生这种情况的任何原因。下面的文本描述提供了更多的上下文。

设置的Details

  • 机器1是一个ArchLinux膝上型计算机,ssh是在其上产生的,它连接到一个运行着SBC的SBC( Orange )。
  • SBC本身通过以太网连接到DSL路由器,IP为192.168.1.150。
  • 笔记本电脑通过WiFi连接到路由器上--使用官方的Raspberry PI WiFi dongle。
  • 还有另一台笔记本电脑(机器2)通过以太网连接到DSL路由器。

使用the 3 Benchmarking链接

当使用iperf3进行基准测试时,膝上型计算机和SBC之间的连接比理论上的56 MBits/秒要小--正如预期的那样,因为这是一个非常“拥挤的2.4GHz”(公寓楼)内的WiFi连接。

更具体地说:在SBC上运行iperf3 -s之后,将在笔记本上执行以下命令:

代码语言:javascript
复制
# 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大约是24 it /秒,从它(-R)下载达到32 it/秒。

带有SSHBenchmarking

既然如此,让我们看看SSH的运行情况。在使用rsyncborgbackup时,我第一次遇到了导致这篇文章的问题-它们都使用SSH作为传输层.因此,让我们看看SSH如何在相同的链接上执行:

代码语言:javascript
复制
# 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平均达到400 SBC/S,即3.2MBits/秒,比预期的24 24MBits/秒要小得多。

为何我们的链路以其容量的13%运行?

也许是我们的/dev/urandom's的错吗?

代码语言:javascript
复制
# cat /dev/urandom | pv -ptebar > /dev/null
834MiB 0:00:04 [ 216MiB/s] [ 208MiB/s]

不,绝对不是。

也许是SBC本身吗?也许这太慢了?让我们尝试运行相同的SSH命令(即向SBC发送数据),但这一次从通过以太网连接的另一台计算机(Machine 2)运行:

代码语言:javascript
复制
# 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守护进程可以(很容易)处理它的以太网链路提供的11 11MBytes/秒(即100‘s/秒)。

在执行此操作时,是否加载了SBC的CPU?

不是的。

所以..。

  • 就网络而言(按照iperf3),我们应该能够达到10倍的速度。
  • 我们的CPU可以轻松地承受负载。
  • ..。我们不涉及任何其他类型的I/O (例如驱动器)。

到底是怎么回事?

<#>Netcat和ProxyCommand到救援

让我们试试普通的旧netcat连接--它们的运行速度是否与我们预期的一样快?

在巴塞尔公约中:

代码语言:javascript
复制
# nc -l -p 9988 | pv -ptebar > /dev/null

在笔记本电脑里:

代码语言:javascript
复制
# cat /dev/urandom | pv -ptebar | nc 192.168.1.150 9988
117MiB 0:00:33 [3.82MiB/s] [3.57MiB/s] 

它起作用了!并以预期的速度运行--更好,更快10倍--速度。

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

代码语言:javascript
复制
# 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协议?

为什么产生的速度有这么大的差别?

这不是一个学术练习-我的borg备份运行速度比这快10倍。我只是不知道为什么:-)

编辑:添加了进程这里的“视频”。计算从ifconfig输出发送的数据包,很明显,在这两个测试中,我们都发送了40 it的数据,在大约30K的数据包中传输--只是在不使用ProxyCommand的情况下要慢得多。

EN

回答 1

Unix & Linux用户

回答已采纳

发布于 2018-04-01 21:09:13

非常感谢在评论中提出意见的人。我把它们都看过了:

带有the转储的Recording包和WireShark中内容的比较

代码语言:javascript
复制
# 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

在记录的数据包中没有任何重要的区别。

用于流量整形的Checking

我不知道这件事--但是在看了"tc“手册之后,我能够证实这一点。

  • tc filter show什么也不回
  • tc class show什么也不回
  • tc qdisc show

...returns这些:

代码语言:javascript
复制
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 

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

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

不,同样的结果。

Finally - Nagle

在发送者中执行一次.

代码语言:javascript
复制
pv data | strace -T -ttt -f ssh 192.168.1.150 'cat | md5sum' 2>bad.log

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

代码语言:javascript
复制
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的算法。您可以搜索并阅读有关它的所有内容--但它的意思是SSH将响应性置于带宽之上--它指示内核立即发送写在这个套接字上的任何内容,而不是“延迟”等待来自远程的确认。

简单地说,这意味着,在默认配置中,SSH不是一种传输数据的好方法--而不是当使用的链接比较慢时(许多WiFi链接就是这种情况)。如果我们在空中发送“大部分是头”的数据包,那么带宽就浪费了!

为了证明这确实是罪魁祸首,我使用LD_PRELOAD“丢弃”了这个特定的syscall:

代码语言:javascript
复制
$ cat force_nagle.c

#include 
#include 
#include 
#include 
#include 

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一样快)。

故事的Morale

永不放弃:-)

如果您确实使用了像rsyncborgbackup这样的工具在SSH上传输数据,并且您的链接很慢,请尝试阻止SSH禁用Nagle (如上面所示)-或者使用ProxyCommand切换SSH以通过nc连接。这可以在$HOME/..ssh/config中自动完成:

代码语言:javascript
复制
$ cat .ssh/config
...
Host orangepi
    Hostname 192.168.1.150
    User root
    Port 22
    # Compression no
    # Cipher None
    ProxyCommand nc %h %p
...

...so表示,今后在ssh/rsync/borgbackup中所有使用"orangepi“作为目标主机的用户都将使用nc进行连接(因此不要使用D21)。

票数 18
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/434825

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档