SSH-Geschwindigkeit über ProxyCommand stark verbessert - aber warum?

13

Die TL; DR-Version

Sehen Sie sich diese ASCII-Besetzung oder dieses Video an und finden Sie Gründe, warum dies geschieht. Die folgende Textbeschreibung bietet mehr Kontext.

Details zum Setup

  • Maschine 1 ist ein Arch Linux-Laptop, auf dem ssheine Verbindung zu einem SBC (Orange PI Zero) hergestellt wird , auf dem Armbian ausgeführt wird.
  • Der SBC selbst ist über Ethernet mit einem DSL-Router verbunden und hat eine IP von 192.168.1.150
  • Der Laptop ist über WLAN mit dem Router verbunden - mithilfe eines offiziellen Raspberry PI-WLAN-Dongles.
  • Es gibt auch einen anderen Laptop (Maschine 2), der über Ethernet mit dem DSL-Router verbunden ist.

Topologie

Benchmarking der Verknüpfung mit iperf3

Beim Benchmarking mit iperf3liegt die Verbindung zwischen Laptop und SBC - wie erwartet - unter den theoretischen 56 MBit / s, da es sich um eine WiFi-Verbindung innerhalb eines sehr "überfüllten 2,4 GHz" (Wohnhaus) handelt .

Genauer gesagt: Nach dem Ausführen iperf3 -sauf dem SBC werden die folgenden Befehle auf dem Laptop ausgeführt:

# 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

Das Hochladen auf den SBC erreicht also im Grunde genommen etwa 24 MBit / s, und das Herunterladen von ihm ( -R) erreicht 32 MBit / s.

Benchmarking mit SSH

Vor diesem Hintergrund wollen wir sehen, wie SSH abschneidet. Ich habe erfahren zuerst die Probleme , die zu diesem Beitrag führt bei der Verwendung rsyncund borgbackup- beide SSH als Transportschicht mit ... Lassen Sie sich also , wie SSH führt auf dem gleichen Link zu sehen:

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

Nun, das ist eine miserable Geschwindigkeit! Deutlich langsamer als die erwartete Verbindungsgeschwindigkeit ... (Falls Sie sich nicht bewusst sind pv -ptevar: Es zeigt die aktuelle und durchschnittliche Datenrate an, die durch die Verbindung geht. In diesem Fall wird das Lesen von /dev/urandomund Senden der Daten über SSH an den SBC festgestellt liegt im Durchschnitt bei 400 KB / s - das sind 3,2 MBit / s, weitaus weniger als die erwarteten 24 MBit / s.)

Warum ist unser Link zu 13% ausgelastet?

Ist es vielleicht unsere /dev/urandomSchuld?

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

Nein, definitiv nicht.

Ist es vielleicht die SBC selbst? Vielleicht ist es zu langsam zu verarbeiten? Versuchen wir, denselben SSH-Befehl auszuführen (dh Daten an den SBC zu senden), diesmal jedoch von einem anderen Computer (Computer 2), der über das Ethernet verbunden ist:

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

Nein, das funktioniert einwandfrei - der SSH-Dämon auf dem SBC kann (leicht) die 11 MB / s (dh die 100 MB / s) verarbeiten, die die Ethernet-Verbindung bereitstellt.

Und ist dabei die CPU des SBC geladen?

CPU ist leicht zu handhaben

Nee.

So...

  • In iperf3Bezug auf das Netzwerk sollten wir in der Lage sein, die 10-fache Geschwindigkeit zu erreichen
  • Unsere CPU kann die Last problemlos aufnehmen
  • ... und wir haben keine andere Art von E / A (z. B. Laufwerke).

Was zum Teufel ist los?

Netcat und ProxyCommand zur Rettung

Versuchen wir es mit einfachen alten netcatVerbindungen. Laufen sie so schnell, wie wir es erwarten würden?

In der SBC:

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

Im Laptop:

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

Es klappt! Und läuft mit der erwarteten - viel besseren, 10x besseren - Geschwindigkeit.

Was passiert also, wenn ich SSH mit einem ProxyCommand ausführe, um nc zu verwenden?

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

Funktioniert! 10x Geschwindigkeit.

Jetzt bin ich ein wenig verwirrt - wenn ein „nackten“ kann ncals ein Proxycommand, nicht im Grunde Sie genau dasselbe zu tun , dass SSH tut? dh Erstellen eines Sockets, Verbinden mit dem Port 22 des SBC und anschließendes Verschieben des SSH-Protokolls?

Warum gibt es diesen großen Unterschied in der resultierenden Geschwindigkeit?

PS: Dies war keine akademische Übung. Mein borgBackup läuft daher 10-mal schneller. Ich weiß nur nicht warum :-)

EDIT : ein „Video“ des Prozesses hinzugefügt hier . Zählt man die von der Ausgabe von ifconfig gesendeten Pakete, wird deutlich, dass wir in beiden Tests 40 MB Daten senden und diese in ungefähr 30 KB Paketen senden - nur viel langsamer, wenn wir sie nicht verwenden ProxyCommand.

ttsiodras
quelle
Pufferung? Ich würde denken, ncverwendet Zeilenpufferung, während sshkeine Pufferung hat. Also (oder wenn ja) beinhaltet der SSH-Verkehr mehr Pakete.
Ralph Rönnquist
Ich bin kein Experte, aber ich denke, Orange 0 hat nur einen USB-Bus, der von der CPU gesteuert wird. Das Netzwerk durchläuft diesen USB-Bus. Die CPU muss per Software Zufallszahlen erstellen Hardware) und gleichzeitig läuft der ssh-cypher und vielleicht auch die ssh-kompression. Ich habe das alles nicht überprüft, also ist es möglich, dass ich etwas Falsches sage.
D'Arcy Nader
1
@ D'ArcyNader: Nein, ich fürchte, du hast es falsch verstanden. Tbe / dev / urandom passiert im Laptop (x86) - und ich habe den gleichen Test von Maschine 2 mit dem SBC durchgeführt, um die Höchstgeschwindigkeit (100 MBit / s) zu erreichen und damit zu beweisen, dass der SBC keine Probleme mit dem Datenverkehr hat. Das Problem tritt nur auf, wenn SSH vom Laptop aus verwendet wird - und wenn ich den SSH-Aufruf (wieder auf der Laptopseite) ändere, um netcat zu verwenden - und weiterhin dev / urandom mache und weiterhin alle Daten weiterleitet - das Problem verschwindet. Übrigens ist der einzelne USB-Bus ein Problem der Raspberry PIs - nicht der Orange PIs.
Ttsiodras
Es tut mir leid, wenn ich dir nicht geholfen habe. und danke für die klärung.
D'Arcy Nader
@ RalphRönnquist: Der ursprüngliche Anwendungsfall, der mich in dieses Kaninchenloch führte, war das Sichern von Dingen über Rsync und Borgbackup. Viele Tools verwenden SSH als Transportmechanismus - und in meinem Fall litt dies darunter. Wenn es sich tatsächlich um das "normale" SSH-Verhalten handelt, würde ich davon ausgehen, dass das Senden von Pull-Anforderungen an alle Sicherungstools, um SSH über einen Netcat-Proxy-Befehl zu erzeugen, Sicherungen auf der ganzen Welt sofort beschleunigen würde! Ich kann nicht glauben, dass ich so eine "riesige" Entdeckung gemacht habe :-) Hier muss etwas anderes passieren.
Ttsiodras

Antworten:

13

Vielen Dank an die Leute, die Ideen in den Kommentaren eingereicht haben. Ich habe sie alle durchgesehen:

Aufzeichnen von Paketen mit tcpdump und Vergleichen der Inhalte in WireShark

# tcpdump -i wlan0 -w good.ssh & \
     cat signature | ssh -o "ProxyCommand nc %h %p" \
        [email protected] 'cat | md5sum' ; \
     killall tcpdump
# tcpdump -i wlan0 -w bad.ssh & \
     cat signature | ssh [email protected] 'cat | md5sum' ; \
     killall tcpdump

Bei den aufgezeichneten Paketen war kein Unterschied von Bedeutung.

Überprüfung auf Traffic Shaping

Hatte keine Ahnung davon - aber nachdem ich mir die "tc" -Manpage angesehen hatte, konnte ich das überprüfen

  • tc filter show gibt nichts zurück
  • tc class show gibt nichts zurück
  • tc qdisc show

... gibt diese zurück:

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 

... die nicht zwischen "ssh" und "nc" zu unterscheiden scheinen - in der Tat bin ich nicht einmal sicher, ob Traffic Shaping auf der Prozessebene funktionieren kann (ich würde erwarten, dass es auf Adressen / Ports / Differentiated funktioniert) Feld Dienste im IP-Header).

Debian Chroot, um potenzielle "Cleverness" im Arch Linux SSH-Client zu vermeiden

Nein, die gleichen Ergebnisse.

Endlich - Nagle

Durchführen einer Strace im Absender ...

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

... und als ich sah, was genau auf dem Socket passiert, über den die Daten übertragen werden, bemerkte ich dieses "Setup", bevor die eigentliche Übertragung beginnt:

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>

Dadurch wird der SSH-Socket so eingerichtet, dass der Nagle-Algorithmus deaktiviert wird. Sie können googeln und alles darüber lesen - was jedoch bedeutet, dass SSH der Reaktionsfähigkeit Vorrang vor der Bandbreite einräumt -, weist es den Kernel an, alles, was auf diesen Socket geschrieben ist, sofort zu übertragen und nicht das Warten auf Bestätigungen von der Fernbedienung zu "verzögern".

Dies bedeutet im Klartext, dass SSH in seiner Standardkonfiguration KEINE gute Möglichkeit zum Transport von Daten ist - nicht, wenn die verwendete Verbindung langsam ist (was bei vielen WiFi-Verbindungen der Fall ist). Wenn wir Pakete über das Mobilfunknetz senden, die "meistens Header" sind, wird die Bandbreite verschwendet!

Um zu beweisen, dass dies tatsächlich der Schuldige war, habe ich LD_PRELOAD verwendet, um diesen speziellen Systemaufruf "fallen zu lassen":

$ 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 [email protected] 'cat >/dev/null'
No, Mr Nagle stays.
No, Mr Nagle stays.
 100MiB 0:00:29 [3.38MiB/s] [3.38MiB/s] [================================>] 100%   

Dort - perfekte Geschwindigkeit (na ja, genauso schnell wie iperf3).

Moral der Geschichte

Gib niemals auf :-)

Wenn Sie Tools wie rsyncoder verwenden borgbackup, die ihre Daten über SSH übertragen, und Ihre Verbindung langsam ist, versuchen Sie, SSH daran zu hindern, Nagle zu deaktivieren (wie oben gezeigt) - oder verwenden Sie ProxyCommand, um SSH für die Verbindung über zu wechseln nc. Dies kann in Ihrer $ HOME / .ssh / config automatisiert werden:

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

... damit alle zukünftigen Verwendungen von "orangepi" als Ziel-Host in ssh / rsync / borgbackup fortan nceine Verbindung herstellen (und Nagle daher in Ruhe lassen).

ttsiodras
quelle