ความเร็ว SSH ได้รับการปรับปรุงอย่างมากผ่าน ProxyCommand - แต่ทำไม?


14

เวอร์ชัน TL; DR

รับชม ASCII นักแสดงหรือวิดีโอนี้ - จากนั้นมาด้วยเหตุผลใด ๆ ว่าทำไมสิ่งนี้จึงเกิดขึ้น คำอธิบายข้อความที่ตามมาให้บริบทเพิ่มเติม

รายละเอียดของการตั้งค่า

  • Machine 1 เป็นแล็ปท็อป Arch Linux ที่sshวางไข่เชื่อมต่อกับ SBC ที่ทำงานโดย Armbian (Orange PI Zero)
  • SBC นั้นเชื่อมต่อผ่านอีเธอร์เน็ตไปยังเราเตอร์ DSL และมี IP 192.168.1.150
  • แล็ปท็อปเชื่อมต่อกับเราเตอร์ผ่าน WiFi - ใช้ดองเกิล Raspberry PI WiFi อย่างเป็นทางการ
  • นอกจากนี้ยังมีแล็ปท็อปอีกเครื่อง (Machine 2) เชื่อมต่อผ่านอีเธอร์เน็ตไปยังเราเตอร์ DSL

โทโพโลยี

การเปรียบเทียบการเชื่อมโยงกับ iperf3

เมื่อเทียบกับการiperf3เชื่อมโยงระหว่างแล็ปท็อปและ SBC น้อยกว่าทฤษฎีที่ 56 Mbits / วินาที - ตามที่คาดไว้ตั้งแต่นี้คือการเชื่อมต่ออินเตอร์เน็ตไร้สายภายใน "2.4GHz แออัด" มาก(อาคารพาร์ทเมนท์)

โดยเฉพาะอย่างยิ่ง: หลังจากทำงาน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 ฉันเคยพบปัญหาที่นำไปสู่การโพสต์นี้เมื่อใช้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) แต่คราวนี้จากเครื่องอื่น (Machine 2) ที่เชื่อมต่อผ่าน Ethernet:

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

ไม่, มันใช้งานได้ดี - SSH daemon บน SBC สามารถ (ได้อย่างง่ายดาย) จัดการ 11MBytes / วินาที (เช่น 100MBits / วินาที) ที่มีการเชื่อมโยงอีเธอร์เน็ต

และซีพียูของ SBC ถูกโหลดระหว่างที่ทำสิ่งนี้

CPU จัดการได้ง่าย

Nope

ดังนั้น...

  • เครือข่ายฉลาด (ตามiperf3) เราควรจะสามารถทำความเร็ว 10 เท่า
  • ซีพียูของเราสามารถรองรับโหลดได้อย่างง่ายดาย
  • ... และเราไม่เกี่ยวข้องกับ 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 เท่า

ดังนั้นจะเกิดอะไรขึ้นถ้าฉันรัน SSH โดยใช้ ProxyCommand เพื่อใช้ nc

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

Works! ความเร็ว 10 เท่า

ตอนนี้ผมสับสนเล็กน้อย - เมื่อใช้ "เปล่า" ncเป็นProxycommandไม่ได้คุณพื้นทำสิ่งเดียวที่แน่นอนว่า SSH ไม่? คือการสร้างซ็อกเก็ตเชื่อมต่อกับพอร์ต 22 ของ SBC จากนั้นจึงตักโพรโทคอล SSH ทับหรือไม่

เหตุใดจึงมีความแตกต่างอย่างมากในความเร็วที่เกิดขึ้น

ป.ล. นี่ไม่ใช่แบบฝึกหัดทางวิชาการ - การborgสำรองข้อมูลของฉันทำงานเร็วขึ้น 10 เท่าด้วยเหตุนี้ ฉันไม่รู้ว่าทำไม :-)

แก้ไข : เพิ่ม "วิดีโอ" ของกระบวนการที่นี่ นับแพ็คเก็ตที่ส่งมาจากการส่งออกของ ifconfig ก็เป็นที่ชัดเจนว่าในการทดสอบทั้งเราจะส่ง 40MB ของข้อมูลการส่งพวกเขาในเวลาประมาณ 30K แพ็คเก็ต - ProxyCommandเพียงแค่ช้ามากเมื่อไม่ได้ใช้


บัฟเฟอร์? ฉันคิดว่าncใช้การบัฟเฟอร์บรรทัดในขณะที่sshไม่มีบัฟเฟอร์ ดังนั้น (หรือถ้ามี) ทราฟฟิก ssh เกี่ยวข้องกับแพ็กเก็ตเพิ่มเติม
Ralph Rönnquist

ฉันไม่ใช่ผู้เชี่ยวชาญ แต่ฉันคิดว่าสีส้ม 0 มีบัส usb เพียงตัวเดียวที่ควบคุมโดย cpu เครือข่ายผ่านบัส usb นั้น cpu ต้องสร้างหมายเลขสุ่มผ่านซอฟต์แวร์ (ไม่มีชิปบนสถาปัตยกรรมแบบนั้นที่ทำผ่าน ฮาร์ดแวร์) และในเวลาเดียวกันก็มี ssh cypher ต่อเนื่องและอาจจะมีการบีบอัด ssh ด้วย ฉันไม่ได้ตรวจสอบทั้งหมดนี้ดังนั้นจึงเป็นไปได้ที่ฉันจะพูดบางอย่างผิดปกติ
D'Arcy Nader

2
@ D'ArcyNader: ไม่ฉันกลัวว่าคุณเข้าใจผิด Tbe / dev / urandom เกิดขึ้นในแล็ปท็อป (x86) - และฉันทำการทดสอบเดียวกันจาก Machine 2 ที่พูดกับ SBC ถึงความเร็วสูงสุด (100MBits / วินาที) และพิสูจน์ว่า SBC ไม่มีปัญหาเกี่ยวกับการจราจร ปัญหาปรากฏขึ้นเมื่อ SSH ถูกใช้จากแล็ปท็อป - และเมื่อฉันเปลี่ยนการร้องขอ SSH (อีกครั้งที่ด้านแล็ปท็อป) เพื่อใช้ netcat - ดังนั้นยังคงทำ dev / urandom และยังคงเก็บข้อมูลทั้งหมด - ปัญหาหายไป และ BTW บัส USB เดียวเป็นปัญหาของ Raspberry PIs ไม่ใช่ Orange PIs
ttsiodras

ฉันขอโทษถ้าฉันไม่ได้ช่วยคุณ และขอขอบคุณสำหรับการชี้แจง
D'Arcy Nader

@ RalphRönnquist: กรณีการใช้งานดั้งเดิมที่นำฉันลงสู่โพรงกระต่ายนี้กำลังสนับสนุนสิ่งต่างๆมากกว่า rsync และ borgbackup เครื่องมือจำนวนมากใช้ SSH เป็นกลไกการขนส่ง - และในกรณีของฉันได้รับความเดือดร้อนด้วยเหตุนี้ หากสิ่งที่ฉันพบคือพฤติกรรม SSH "มาตรฐาน" ดังนั้นฉันคาดหวังว่าการส่งคำขอดึงไปยังเครื่องมือสำรองข้อมูลทั้งหมดเพื่อวางไข่ SSH ผ่านทาง netcat ProxyCommand จะเร่งการสำรองข้อมูลทั่วโลกทันที! ฉันไม่อยากจะเชื่อเลยว่าฉันได้ค้นพบ "ใหญ่" ดังกล่าว :-) อย่างอื่นต้องเกิดขึ้นที่นี่
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 เพื่อ "ดรอป" syscall เฉพาะนี้:

$ 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 และการเชื่อมโยงของคุณช้าหนึ่งพยายามหยุด 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
ttsiodras

เพิ่มตัวเองลงในข้อผิดพลาด ใครจะรู้บางสิ่งบางอย่างอาจเกิดขึ้นในที่สุด! การสอบสวนที่ยอดเยี่ยมในทุกกรณี
static_rtti
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.