ProxyCommand ile SSH hızı büyük ölçüde arttı - ama neden?


14

TL; DR versiyonu

Bu ASCII kadrosunu veya bu videoyu izleyin - ardından bunun gerçekleşmesinin herhangi bir nedenini bulun. Aşağıdaki metin açıklaması daha fazla bağlam sağlar.

Kurulum ayrıntıları

  • Makine 1, sshArmbian çalışan bir SBC'ye (Turuncu PI Sıfır) bağlanan bir Arch Linux dizüstü bilgisayardır .
  • SBC'nin kendisi Ethernet üzerinden bir DSL yönlendiriciye bağlıdır ve 192.168.1.150'lik bir IP'ye sahiptir.
  • Dizüstü bilgisayar, resmi bir Ahududu PI WiFi dongle'ı kullanarak WiFi üzerinden yönlendiriciye bağlanır.
  • Ethernet üzerinden DSL yönlendiriciye bağlı başka bir dizüstü bilgisayar (Makine 2) var.

Topoloji

Bağlantıyı iperf3 ile karşılaştırma

İle benchmarked zaman iperf3laptop arasındaki bağlantıyı ve SBC az teorik 56 Mbit / sn daha - beklendiği gibi, bu çok "kalabalık 2.4GHz" içinde WiFi bağlantısı olduğundan (apartmanın) .

Daha spesifik olarak: iperf3 -sSBC üzerinde çalıştıktan sonra , dizüstü bilgisayarda aşağıdaki komutlar yürütülür:

# 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

Temel olarak, SBC'ye yükleme yaklaşık 24MBits / sn'ye ve ondan indirme ( -R) 32MBits / sn'ye ulaşır.

SSH ile karşılaştırma

Bu göz önüne alındığında, SSH'nin nasıl yürüdüğüne bakalım. İlk önce bu gönderiye yol açan sorunları yaşadım rsyncve borgbackupher ikisi de SSH'yi bir taşıma katmanı olarak kullanıyor ... Öyleyse SSH'nin aynı bağlantıda nasıl performans gösterdiğini görelim:

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

Bu berbat bir hız! Beklenen bağlantı hızından çok daha yavaş ... (Farkında değilseniz pv -ptevar: geçerli ve ortalama veri hızını gösterir. Bu durumda /dev/urandomSSH üzerinden veri okumayı ve SBC'ye veri göndermeyi görüyoruz. ortalama 400 KB / sn'ye ulaşıyor - yani 3,2 MB / sn, beklenen 24 MB / sn'den çok daha az bir rakam.)

Bağlantımız neden kapasitesinin% 13'ünde çalışıyor?

Belki de bizim /dev/urandomhatamız mı?

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

Hayır, kesinlikle hayır.

Belki SBC'nin kendisi midir? Belki de işlemek için çok yavaş? Aynı SSH komutunu (yani SBC'ye veri gönderme) çalıştırmayı deneyelim, ancak bu sefer Ethernet üzerinden bağlı başka bir makineden (Makine 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] 

Hayır, bu iyi çalışıyor - SBC'deki SSH arka plan programı Ethernet bağlantısının sağladığı 11MBytes / sn (yani 100MBits / sn) işleyebilir (kolayca).

Ve bunu yaparken SBC'nin CPU'su yüklü mü?

CPU kolayca idare ediyor

Hayır!

Yani...

  • ağ üzerinden (başına iperf3) hızı 10 kat yapabilmeliyiz
  • CPU'muz yükü kolayca kaldırabilir
  • ... ve başka herhangi bir I / O (örneğin sürücüler) içermiyoruz.

Ne halt oluyor?

Netcat ve Proxy

Basit eski netcatbağlantıları deneyelim - beklediğimiz kadar hızlı çalışıyorlar mı?

SBC'de:

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

Dizüstü bilgisayarda:

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

İşe yarıyor! Ve beklenen hızda - çok daha iyi, 10 kat daha iyi - çalışır.

Peki SSC'yi nc kullanmak için bir ProxyCommand kullanarak çalıştırırsam ne olur?

# 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]

İşler! 10x hız.

Şimdi biraz kafam karıştı - bir "çıplak" ncolarak kullanırken Proxycommand, temelde SSH'nin yaptığı ile aynı şeyi yapmıyor musunuz? yani bir soket oluşturmak, SBC'nin portuna 22 bağlanmak ve sonra SSH protokolünü bunun üzerine küreklemek mi?

Ortaya çıkan hızda neden bu kadar büyük bir fark var?

Not: Bu akademik bir çalışma değildi - borgyedeklemem bundan dolayı 10 kat daha hızlı çalışıyor. Neden bilmiyorum :-)

EDIT : Buraya sürecin bir "video" eklendi . İfconfig çıktısından gönderilen paketleri sayarsak, her iki testte de 40MB veri gönderiyoruz, bunları yaklaşık 30K pakette gönderiyoruz - kullanmadığınızda çok daha yavaş ProxyCommand.


tamponlama? Ben nctamponlama kullanır iken ssh, tamponlama kullanır düşünürdüm . Yani (ya da öyleyse) ssh trafiği daha fazla paket içerir.
Ralph Rönnquist

Ben uzman değilim ama turuncu 0 cpu tarafından kontrol edilen sadece bir usb veri yolu olduğunu düşünüyorum, ağ bu usb veri yolundan geçiyor, cpu yazılım aracılığıyla rastgele sayı oluşturmak zorunda (bu tür mimaride bunu yapan bir yonga yok donanım) ve aynı zamanda devam eden ssh cypher ve belki de ssh sıkıştırma da var. Tüm bunları kontrol etmedim, bu yüzden yanlış bir şey söylüyorum.
D'Arcy Nader

2
@ D'ArcyNader: Hayır, korkarım yanlış anladın. Tbe / dev / urandom dizüstü bilgisayarda (x86) olur - ve aynı testi SBC ile konuşan, en yüksek hızlara (100MBits / sn) ulaşan ve böylece SBC'nin trafikle ilgili bir sorunu olmadığını kanıtlayan Test 2'den yaptım. Sorun yalnızca SSH dizüstü bilgisayardan kullanıldığında ortaya çıkıyor - ve SSC çağrısını (yine dizüstü bilgisayar tarafında) netcat kullanmak için değiştirdiğimde ortaya çıkıyor - bu yüzden hala dev / urandom yapıyor ve hala tüm verileri borulıyor - sorun kayboluyor. Ve BTW, tek USB veri yolu, Raspberry PI'lerin bir sorunudur - Turuncu PI'lerin değil.
ttsiodras

Sana yardım etmediysem özür dilerim. ve açıklama için teşekkür ederim.
D'Arcy Nader

@ RalphRönnquist: Beni bu tavşan deliğinden aşağı çeken orijinal kullanım durumu, rsync ve borgbackup üzerinde işleri destekliyordu. Birçok araç SSH'yi bir taşıma mekanizması olarak kullanır - ve benim durumumda bu nedenle acı çekti. Eğer yaşadığım şey gerçekten "standart" SSH davranışı ise, o zaman bir netcat ProxyCommand aracılığıyla SSH ortaya çıkarmak için tüm yedekleme araçlarına çekme istekleri göndermenin anında tüm gezegendeki yedeklemeleri hızlandıracağını beklerdim! Böyle bir "büyük" keşif yaptığım inanamıyorum :-) Burada başka bir şey olmalı.
ttsiodras

Yanıtlar:


14

Yorumlarda fikir gönderenlere çok teşekkürler. Hepsinden geçtim:

Tcpdump ile paketleri kaydetme ve WireShark'taki içerikleri karşılaştırma

# 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

Kaydedilen paketlerde herhangi bir önem farkı yoktu.

Trafik şekillendirme kontrolü

Bu konuda hiçbir fikrim yoktu - ama "tc" man sayfasına baktıktan sonra, bunu doğrulayabildim

  • tc filter show hiçbir şey döndürmez
  • tc class show hiçbir şey döndürmez
  • tc qdisc show

... bunları döndürür:

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" ve "nc" arasında ayrım yapmıyor gibi görünüyor - aslında, trafik şekillendirmenin işlem düzeyinde çalışıp çalışmadığından bile emin değilim (adresler / bağlantı noktaları / Farklılaştırılmış olarak çalışmasını beklerim) IP Üstbilgisindeki Hizmetler alanı).

Debian Chroot, Arch Linux SSH istemcisinde potansiyel "zekayı" önlemek için

Hayır, aynı sonuçlar.

Sonunda - Nagle

Göndericide bir strace gerçekleştirme ...

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

... ve verileri ileten sokette tam olarak ne olduğuna baktığımda, gerçek iletim başlamadan önce bu "kurulumu" fark ettim:

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>

Bu, SSH soketini Nagle algoritmasını devre dışı bırakacak şekilde ayarlar. Google'ı okuyabilir ve her şeyi okuyabilirsiniz - ancak bunun anlamı, SSH'nin bant genişliği üzerinde yanıt vermeye öncelik vermesidir - çekirdeğe uzaktan kumandadan onay beklerken "gecikme" değil, bu sokete yazılan herhangi bir şeyi hemen iletmesini söyler.

Bunun basit bir ifadeyle, varsayılan yapılandırmasında, SSH'nin verileri taşımak için iyi bir yol olmadığı anlamına gelir - kullanılan bağlantı yavaş olduğunda (birçok WiFi bağlantısı için durum böyle değildir). Şebeke üzerinden "çoğunlukla başlık" olan paketler göndersek, bant genişliği boşa gider!

Bunun gerçekten suçlu olduğunu kanıtlamak için, LD_PRELOAD kullandım ve bu özel sistemi "bıraktım":

$ 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%   

Orada - mükemmel hız (iyi, iperf3 kadar hızlı).

Hikayenin morali

Asla pes Etme :-)

Eğer böyle kullanım araçları yaparsanız rsyncya borgbackupkullanılarak veya - Bu taşıma verilerini SSH üzerinden, ve bağlantı yavaş biridir (yukarıda gösterildiği gibi) Nagle devre dışı bırakmasını SSH durdurma deneyin ProxyCommandüzerinden bağlanmak için anahtar SSH için nc. Bu, $ HOME / .ssh / config dosyasında otomatikleştirilebilir:

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

... böylece ssh / rsync / borgbackup içinde hedef konakçı olarak "orangepi" nin gelecekteki tüm kullanımları ncbu nedenle bağlanmak için kullanılır (ve bu nedenle Nagle'ı yalnız bırakır).


Teşekkürler, hayatımı kurtardın! Bunu kontrol etmek için neden bir ayar olmadığını anlamak için ssh milletiyle iletişime geçmeyi denediniz mi?
static_rtti

1
Bulgularımın da size yardımcı olduğuna sevindim! SSH
milletiyle

Hataya kendimi ekledim. Kim bilir, sonunda bir şeyler olabilir! Her durumda büyük soruşturma.
static_rtti
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.