ProxyCommandを使用してSSHの速度が大幅に向上しましたが、なぜですか?


14

TL; DRバージョン

このASCIIキャストまたはこのビデオをご覧ください。次に、これが発生する理由を考えてください。次のテキスト説明は、より多くのコンテキストを提供します。

セットアップの詳細

  • マシン1はArch Linuxラップトップであり、その上にsshArmbian実行SBC(オレンジPIゼロ)に接続されます。
  • SBC自体はイーサネット経由でDSLルーターに接続され、192.168.1.150のIPを持っています
  • ラップトップはWiFi経由でルーターに接続されます-公式のRaspberry PI WiFiドングルを使用します。
  • イーサネット経由でDSLルーターに接続された別のラップトップ(マシン2)もあります。

トポロジー

iperf3によるリンクのベンチマーク

でベンチマークするとiperf3、ラップトップとSBC間のリンクは理論上の56 MBits / sec未満です。これは、非常に「混雑した2.4GHz」(アパート)内のWiFi接続であるためです。

具体的iperf3 -sには、SBCで実行した後、ラップトップで次のコマンドが実行されます。

# 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 /秒に達し、そこからのダウンロード(-R)は32MBits /秒に達します。

SSHによるベンチマーク

それを踏まえて、SSHの運命を見てみましょう。rsyncandの使用時に、この投稿につながった問題を最初に経験しましたborgbackup-両方ともトランスポートレイヤーとして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およびSBCにSSH経由でデータを送信します平均で400KB / sに達します。つまり、3.2MBits / secで、予想される24MBits / secよりもはるかに少ない数値です。

リンクが容量の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] 

できます!そして、予想通りの速度-はるかに良い、10倍の速度-で動作します。

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トラフィックにはより多くのパケットが含まれます。
ラルフロンキスト

私は専門家ではありませんが、オレンジ0にはCPUによって制御されるUSBバスが1つしかないと思います。ネットワークはそのUSBバスを通過し、CPUはソフトウェアを介して乱数を作成する必要があります(その種類のアーキテクチャにはそれを行うチップはありませんハードウェア)同時に、進行中のssh暗号化と、おそらくssh圧縮もあります。私はこれをすべてチェックしなかったので、何か間違ったことを言っている可能性があります。
ダーシーネーダー

2
@ D'ArcyNader:いいえ、間違っていると思います。Tbe / dev / urandomはラップトップ(x86)で発生します。SBCと通信するマシン2から同じテストを行い、最高速度(100MBits /秒)に達し、SBCにトラフィックの処理に問題がないことを証明しました。この問題は、SSHをラップトップから使用する場合(およびラップトップ側でSSH呼び出しを変更してnetcatを使用する場合)にのみ現れます。したがって、dev / urandomを実行し、すべてのデータをパイピングします-問題はなくなります。ところで、単一のUSBバスは、オレンジPIではなく、ラズベリーPIの問題です。
ttsiodras

助けてくれなかったらごめんなさい。明確化していただきありがとうございます。
ダーシーネーダー

@RalphRönnquist:このうさぎの穴に私を導いた元のユースケースは、rsyncとborgbackupで物事をバックアップしていました。多くのツールはトランスポートメカニズムとしてSSHを使用します-私の場合、このために苦しみました。私が経験していることが、実際に「標準の」SSHの振る舞いである場合、netcat ProxyCommandを介してSSHを生成するためにすべてのバックアップツールにプルリクエストを送信すると、瞬時に世界中のバックアップが高速化されます!私はそのような「巨大な」発見をしたとは信じられない。
ttsiodras

回答:


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

送信者でstraceを実行しています...

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と同じくらい速い)。

物語のモラル

あきらめないで :-)

あなたのような使用ツールを実行する場合と、rsyncまたはborgbackupまたは使用して-その輸送自分のデータをSSHの上に、そしてあなたのリンクが遅いものです、(上記のように)のNagleを無効からSSHを停止してみてください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
...

...したがって、ssh / rsync / borgbackupでターゲットホストとして「orangepi」を使用ncすると、今後は接続に使用されます(したがって、Nagleはそのままにします)。


ありがとう、あなたは私の命を救った!これを制御する設定がない理由を理解するためにsshの人々に連絡してみましたか?
static_rtti

1
私の調査結果もあなたに役立ってうれしいです!SSHの人々に連絡することに関しては、はい-しかし、何も起こりませんでした。最終的には bugzilla.mindrot.org/show_bug.cgi?id=2848
ttsiodras

自分をバグに追加しました。誰が知っている、何かが最終的に起こるかもしれません!いずれにせよ、素晴らしい調査。
static_rtti
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.